Cursor Pagination मोबाइल डेवलपमेंट में — यह क्या है, सिद्धांत और कार्यान्वयन

लेखक: IT Sectr प्रकाशित: 2026-03-11 पढ़ने का समय: 9 मिनट

Cursor Pagination एक क्रमबद्ध रिकॉर्ड सेट में नेविगेट करने के लिए एक अद्वितीय कर्सर का उपयोग करके डेटा को पृष्ठांकित रूप से लोड करने की एक विधि है। GraphQL Specification (2025) के अनुसार, कर्सर-आधारित पेजिनेशन गतिशील डेटा के साथ काम करने वाले API के लिए अनुशंसित मानक है। Cursor pagination Offset दृष्टिकोण की मुख्य कमियों को समाप्त करता है: इंसर्शन के दौरान अस्थिरता और बड़े ऑफसेट पर प्रदर्शन में गिरावट।

मुख्य बिंदु

  • Cursor Pagination एक पेजिनेशन विधि है जहाँ प्रत्येक रिकॉर्ड में नेविगेशन के लिए एक अद्वितीय कर्सर पहचानकर्ता होता है।
  • कर्सर डेटा सेट में एक अद्वितीय स्थिति मार्कर है (आमतौर पर ID, UUID, timestamp) जो इंसर्शन पर नहीं बदलता है।
  • स्थिरता — अनुरोधों के बीच जोड़े गए नए रिकॉर्ड कर्सर को स्थानांतरित नहीं करते, डुप्लिकेट और अंतराल को समाप्त करते हैं।
  • प्रदर्शन — WHERE id > cursor क्वेरी बड़े डेटासेट पर गति खोए बिना इंडेक्स का कुशलतापूर्वक उपयोग करती है।
  • सीमा — कर्सर पेजिनेशन पृष्ठ संख्या द्वारा नेविगेशन का समर्थन नहीं करता (आप पृष्ठ 5 पर नहीं जा सकते)।

Cursor Pagination क्या है?

Cursor Pagination एक पृष्ठांकित लोडिंग विधि है जिसमें सर्वर डेटा के साथ एक विशेष संकेतक — कर्सर — लौटाता है। क्लाइंट अगले अनुरोध में इस कर्सर का उपयोग रिकॉर्ड के अगले बैच को प्राप्त करने के लिए करता है। कर्सर वर्तमान पृष्ठ के अंतिम तत्व का एक अद्वितीय पहचानकर्ता है।

Offset पेजिनेशन के विपरीत, जहाँ क्लाइंट कहता है “मुझे 20 रिकॉर्ड के साथ पृष्ठ 5 दें,” कर्सर पेजिनेशन अलग तरीके से काम करता है: “मुझे ID = 83 वाले रिकॉर्ड के बाद 20 रिकॉर्ड दें।” सर्वर WHERE id > 83 और LIMIT 20 के साथ एक क्वेरी निष्पादित करता है। यह दृष्टिकोण गारंटी देता है कि प्रत्येक रिकॉर्ड इंसर्शन की परवाह किए बिना ठीक एक पृष्ठ में आता है।

कर्सर पेजिनेशन की अवधारणा को Relay Connection (GraphQL) विनिर्देश के कारण व्यापक रूप से अपनाया गया, जिसने कर्सर-आधारित पेजिनेशन को आधुनिक API के लिए मानक बना दिया। Relay प्रतिक्रिया प्रारूप को परिभाषित करता है: edges (कर्सर के साथ रिकॉर्ड की सरणी), pageInfo (hasNextPage, hasPreviousPage, startCursor, endCursor)।

इतिहास

कर्सर पेजिनेशन कोई नई तकनीक नहीं है — इसका उपयोग वेब से बहुत पहले डेटाबेस में किया जाता था। SQL में इसे keyset pagination या seek method कहा जाता है। यह विधि 2015 में Relay विनिर्देश के प्रकाशन के बाद API में लोकप्रिय हुई, जिसने HTTP ट्रांसपोर्ट पर एकरूपता के लिए कर्सर प्रारूप को base64-एन्कोडेड स्ट्रिंग के रूप में औपचारिक रूप दिया।

कर्सर पेजिनेशन कैसे काम करता है

कर्सर पेजिनेशन का मूल सिद्धांत यह है कि क्वेरी स्थिति निर्धारण के लिए ऑफ़सेट के बजाय एक अनुक्रमित फ़ील्ड पर WHERE शर्त का उपयोग करती है। आगे की दिशा के लिए WHERE id > last_id का उपयोग किया जाता है; पीछे की दिशा के लिए WHERE id < first_id का। B-tree इंडेक्स कर्सर के बाद पहला रिकॉर्ड O(log n) में ढूँढता है, जो स्थिर प्रतिक्रिया समय प्रदान करता है।

sql
-- कर्सर '83' के बाद 20 रिकॉर्ड प्राप्त करें
SELECT id, title, created_at
FROM posts
WHERE id < 83
ORDER BY id DESC
LIMIT 20;

-- कर्सर '83' से पहले 20 रिकॉर्ड प्राप्त करें (पीछे)
SELECT id, title, created_at
FROM posts
WHERE id > 83
ORDER BY id ASC
LIMIT 20;

कर्सर प्रारूप

कर्सर सरल (एक ID मान) या जटिल (कई फ़ील्ड से संयुक्त) हो सकता है। सरल कर्सर रिकॉर्ड की प्राथमिक कुंजी होते हैं, उदाहरण के लिए, ऑटो-इंक्रीमेंट id या UUID। संयुक्त कर्सर का उपयोग गैर-अद्वितीय फ़ील्ड द्वारा सॉर्टिंग के लिए किया जाता है, उदाहरण के लिए (created_at, id), जहाँ id समान टाइमस्टैम्प होने पर विशिष्टता सुनिश्चित करता है।

एक विशिष्ट API प्रारूप base64-एन्कोडेड स्ट्रिंग के रूप में कर्सर है। सर्वर कर्सर को डीकोड करता है, मान निकालता है, और SQL क्वेरी बनाता है। Base64 एन्कोडिंग कर्सर की आंतरिक संरचना को क्लाइंट से छिपाती है और पिछड़ी संगतता को तोड़े बिना प्रारूप बदलने की अनुमति देती है। क्लाइंट प्रतिक्रिया के endCursor फ़ील्ड में कर्सर प्राप्त करता है और उन्हें अगले अनुरोध में स्ट्रिंग के रूप में पास करता है।

आगे और पीछे नेविगेशन

कर्सर पेजिनेशन द्विदिश नेविगेशन का समर्थन करता है। आगे की गति (next) के लिए, वर्तमान पृष्ठ के अंतिम तत्व के कर्सर का उपयोग किया जाता है; पीछे (previous) के लिए, पहले तत्व के कर्सर का। अनुरोध में after और before पैरामीटर दिशा निर्धारित करते हैं: after कर्सर के बाद रिकॉर्ड लेता है, before कर्सर से पहले रिकॉर्ड लेता है।

Cursor बनाम Offset पेजिनेशन

कर्सर और Offset पेजिनेशन के बीच चयन API डिज़ाइन करते समय प्रमुख वास्तुशिल्प निर्णयों में से एक है। प्रत्येक विधि में ताकत और कमज़ोरियाँ हैं जो इसकी प्रयोज्यता निर्धारित करती हैं। Cursor pagination गतिशील डेटा वाले परिदृश्यों में जीतता है; Offset मनमाना नेविगेशन वाले परिदृश्यों में।

विशेषताCursorOffset
इंसर्शन पर स्थिरताउच्च (कोई डुप्लिकेट नहीं)निम्न (पृष्ठ स्थानांतरण)
बड़े डेटासेट पर प्रदर्शनO(log n) — स्थिरO(n) — वृद्धि के साथ घटता है
पृष्ठ संख्या द्वारा नेविगेशननहींहाँ (page=5)
कार्यान्वयन जटिलतामध्यमनिम्न
REST समर्थनcursor/before/afterpage/offset
GraphQL समर्थनRelay मानकअनुशंसित नहीं

Offset बड़े पैमाने पर क्यों विफल होता है

Offset पेजिनेशन OFFSET स्थिति तक पूर्ण तालिका स्कैन करता है। offset=100000 पर, डेटाबेस 100000 पंक्तियाँ पढ़ता और छोड़ता है, भले ही LIMIT 20 हो। MySQL और PostgreSQL OFFSET को अनुकूलित नहीं कर सकते — यह SQL में LIMIT/OFFSET कार्यान्वयन की एक विशेषता है। कर्सर पेजिनेशन B-tree इंडेक्स का उपयोग करता है जो O(log n) में स्थिति ढूँढता है।

एक अतिरिक्त Offset समस्या पीछे की ओर पेजिनेट करते समय रिकॉर्ड “छोड़ना” है। यदि किसी उपयोगकर्ता ने पृष्ठ 5 लोड किया और उसी समय नए रिकॉर्ड जोड़े गए, तो पृष्ठ 6 का अनुरोध करने पर वे पृष्ठ 5 के रिकॉर्ड को फिर से देखेंगे या नए को खो देंगे। Cursor pagination इस परिदृश्य को पूरी तरह से समाप्त करता है: कर्सर सेट में एक विशिष्ट स्थान को इंगित करता है, और इंसर्शन स्थिति नहीं बदलते हैं।

Cursor Pagination का कार्यान्वयन

आइए बैकएंड (Kotlin + Spring) और क्लाइंट (Android + Retrofit) पर कर्सर पेजिनेशन कार्यान्वयन देखें। सर्वर after, before, limit पैरामीटर स्वीकार करता है और कर्सर और pageInfo के साथ रिकॉर्ड की सूची लौटाता है। एक विशिष्ट प्रतिक्रिया में पेजिनेशन UI प्रबंधित करने के लिए hasNextPage और hasPreviousPage होते हैं।

kotlin
@GetMapping("/posts")
fun getPosts(
    @RequestParam after: Long?,
    @RequestParam(defaultValue = "20") limit: Int
): CursorResponse<Post> {
    val cursor = after ?: Long.MAX_VALUE
    val posts = repository.findByIdLessThanOrderByIdDesc(
        cursor, PageRequest.of(0, limit)
    )
    val endCursor = posts.lastOrNull()?.id
    return CursorResponse(
        data = posts,
        pageInfo = PageInfo(
            hasNextPage = posts.size == limit,
            endCursor = endCursor
        )
    )
}

Android पर क्लाइंट कार्यान्वयन

क्लाइंट पर, कर्सर पेजिनेशन Paging 3 से PagingSource के माध्यम से कार्यान्वित किया जाता है, जहाँ कुंजी एक कर्सर (Long) है। PagingSource.load LoadParams.key प्राप्त करता है — अंतिम लोड किए गए रिकॉर्ड का कर्सर। LoadResult.Page डेटा और nextKey — अगले पृष्ठ के लिए कर्सर — लौटाता है। जब nextKey = null, पेजिनेशन पूरा हो जाता है।

kotlin
// Retrofit API
interface PostApi {
    @GET("posts")
    suspend fun getPosts(
        @Query("after") after: Long?,
        @Query("limit") limit: Int = 20
    ): CursorResponse<Post>
}

// कर्सर कुंजी के साथ PagingSource
class PostPagingSource(
    private val api: PostApi
) : PagingSource<Long, Post>() {

    override suspend fun load(
        params: LoadParams<Long>
    ): LoadResult<Long, Post> = try {
        val response = api.getPosts(
            after = params.key,
            limit = params.loadSize
        )
        val nextKey = response.pageInfo.endCursor
        LoadResult.Page(
            data = response.data,
            prevKey = null,
            nextKey = nextKey
        )
    } catch (e: Exception) {
        LoadResult.Error(e)
    }
}

Relay के माध्यम से GraphQL कार्यान्वयन

GraphQL में, कर्सर पेजिनेशन Relay Connection पैटर्न के माध्यम से कार्यान्वित किया जाता है। प्रत्येक प्रकार में एक Connection (pageInfo और edges के साथ) और एक Edge (node + cursor) होता है। क्वेरी first, after, last, before पैरामीटर पास करती है। सर्वर लौटाता है कर्सर के साथ edges की एक सरणी और hasNextPage/hasPreviousPage के साथ pageInfo।

Cursor Pagination का उपयोग कब करें

कर्सर पेजिनेशन गतिशील डेटा के साथ काम करने वाले API के लिए अनुशंसित है जहाँ रिकॉर्ड बार-बार जोड़े या हटाए जाते हैं। उत्कृष्ट उदाहरण: सोशल नेटवर्क में समाचार फ़ीड, चैट संदेश, लेन-देन इतिहास, पोस्ट टिप्पणियाँ। इन सभी परिदृश्यों में, संगति और डुप्लिकेट की अनुपस्थिति महत्वपूर्ण है।

  • चैट और मैसेंजर — प्रत्येक नया संदेश सूची के शीर्ष पर जोड़ा जाता है। Offset पेजिनेशन प्रत्येक नए संदेश के साथ बाधित होता है।
  • सोशल नेटवर्क और फ़ीड — पोस्ट लगातार प्रकाशित होते हैं। कर्सर पेजिनेशन गारंटी देता है कि उपयोगकर्ता एक भी पोस्ट न चूके।
  • ऑर्डर और लेन-देन इतिहास — डेटा कम बार बदलता है, लेकिन वित्तीय रिपोर्टिंग के लिए संगति महत्वपूर्ण है।
  • बड़े डेटा वॉल्यूम वाले API — लाखों रिकॉर्ड। Cursor pagination प्रदर्शन बनाए रखता है जहाँ Offset धीमा होने लगता है।
  • GraphQL APIs — Relay मानक को विनिर्देश अनुपालन के लिए कर्सर-आधारित पेजिनेशन की आवश्यकता होती है।
  • अनंत स्क्रॉल वाले मोबाइल ऐप्स — उपयोगकर्ता नीचे स्क्रॉल करता है, नए बैच लोड करता है। कर्सर दृष्टिकोण बिना डुप्लिकेट के एक सहज UX प्रदान करता है।

कब कर्सर पेजिनेशन उपयुक्त नहीं है

ऐसे परिदृश्य हैं जहाँ Offset पेजिनेशन अधिक सुविधाजनक है: एडमिन पैनल जहाँ पृष्ठ संख्या द्वारा नेविगेशन की आवश्यकता है; पेजिनेशन के साथ खोज जहाँ परिणाम बदल सकते हैं; रिपोर्ट और विश्लेषण जहाँ पृष्ठ 5 के लिए एक निश्चित लिंक की आवश्यकता है। इन मामलों में, कर्सर के लाभ कार्यान्वयन जटिलता से अधिक नहीं होते हैं।

कर्सर पेजिनेशन एक मनमाना पृष्ठ पर “कूदने” का समर्थन नहीं करता — उपयोगकर्ता “पृष्ठ 5” पर क्लिक करके वहाँ नहीं जा सकता। यह एक वास्तुशिल्प सीमा है: पृष्ठों की कुल संख्या गिनने के लिए एक अलग COUNT क्वेरी की आवश्यकता होती है, जो बड़ी तालिकाओं के लिए महँगी हो सकती है। ऐसे मामलों में, एक हाइब्रिड दृष्टिकोण: डेटा के लिए कर्सर + पेजिनेशन के लिए count।

अक्सर पूछे जाने वाले प्रश्न

Cursor Pagination में कर्सर क्या है?

कर्सर एक अद्वितीय रिकॉर्ड पहचानकर्ता है जो डेटा सेट में एक स्थान को इंगित करता है। यह सरल (एक रिकॉर्ड ID) या संयुक्त (कई फ़ील्ड) हो सकता है। क्लाइंट पृष्ठ पर अंतिम रिकॉर्ड का कर्सर प्राप्त करता है और अगला बैच प्राप्त करने के लिए इसे अगले अनुरोध में पास करता है।

Cursor Pagination Offset से बेहतर क्यों है?

Cursor pagination स्थानांतरण के अधीन नहीं है जब नए रिकॉर्ड जोड़े जाते हैं — प्रत्येक तत्व ठीक एक पृष्ठ में आता है। यह पहली n पंक्तियों को स्कैन करने के बजाय इंडेक्स का उपयोग करके बड़े वॉल्यूम पर गति भी बनाए रखता है। Offset सरल है लेकिन गतिशील डेटा के लिए अस्थिर है।

क्या GraphQL के बिना कर्सर पेजिनेशन लागू किया जा सकता है?

हाँ, कर्सर पेजिनेशन GraphQL से बंधा नहीं है। इसे किसी भी REST API में कर्सर को क्वेरी पैरामीटर ?after=83&limit=20 के रूप में पास करके लागू किया जा सकता है। प्रतिक्रिया में endCursor और hasNextPage के साथ pageInfo होना चाहिए — यह क्लाइंट को आंतरिक कर्सर संरचना को जाने बिना लोडिंग प्रबंधित करने की अनुमति देता है।

कौन सा कर्सर उपयोग करें — ID, UUID या timestamp?

ऑटो-इंक्रीमेंट ID सबसे अच्छा विकल्प है: एकरस रूप से बढ़ता है, बदलता नहीं है, कुशलतापूर्वक अनुक्रमित होता है। UUID v7 (समय-क्रमबद्ध) भी काम करता है। टाइमस्टैम्प एक ही समय में डुप्लिकेट उत्पन्न कर सकते हैं, इसलिए इसे ID के साथ जोड़ें: (created_at, id) कर्सर विशिष्टता की गारंटी के लिए।

कर्सर पेजिनेशन के साथ पृष्ठों की कुल संख्या कैसे पता करें?

कर्सर पेजिनेशन पृष्ठों की कुल संख्या प्रदान नहीं करता — यह इसकी सीमा है। यदि आपको कुल जानकारी चाहिए, तो समान फ़िल्टर के साथ एक अलग COUNT क्वेरी निष्पादित करें। बड़ी तालिकाओं के लिए, EXPLAIN के माध्यम से अनुमानित गणना या एनालिटिक्स से कैश्ड कुल का उपयोग करें।

सारांश

  • Cursor Pagination एक पेजिनेशन विधि है जिसमें ऑफ़सेट के बजाय अद्वितीय रिकॉर्ड पहचानकर्ता द्वारा नेविगेशन होता है।
  • कर्सर इंसर्शन पर सेट स्थिरता की गारंटी देता है: नए रिकॉर्ड पहले से लोड किए गए पृष्ठों को स्थानांतरित नहीं करते हैं।
  • प्रदर्शन बड़े डेटा वॉल्यूम पर B-tree इंडेक्स उपयोग के कारण उच्च (O(log n)) बना रहता है।
  • Cursor pagination गतिशील डेटा के लिए उपयुक्त है: चैट, समाचार फ़ीड, लेन-देन, टिप्पणियाँ।
  • मुख्य सीमा पृष्ठ संख्या द्वारा नेविगेशन की कमी और मनमाना पृष्ठ पर कूदने में असमर्थता है।
  • कार्यान्वयन कर्सर के बाद WHERE id, after/before पैरामीटर और प्रतिक्रिया में pageInfo का उपयोग करता है।
  • मानक — Relay Connection GraphQL, लेकिन कर्सर पैरामीटर वाले REST APIs भी व्यापक रूप से उपयोग किए जाते हैं।

हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे

IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।

परियोजना पर चर्चा करें

यह भी पढ़ें