গোপন বাগ ছাড়াই স্থিতিশীল API তালিকার জন্য কার্সার পেজিনেশন
কার্সার পেজিনেশন ডেটা পরিবর্তিত হলে তালিকাকে স্থির রাখে। জানুন কেন ইনসার্ট ও ডিলিট হলে অফসেট পেজিং ভেঙে পড়ে, এবং কীভাবে পরিষ্কার কার্সার বাস্তবায়ন করবেন।

সমস্যা: তালিকা যা আপনার তালু থেকে বদলে যায়
আপনি একটি ফিড খুললেন, একটু স্ক্রল করলেন, এবং সবকিছু স্বাভাবিক মনে হলো যতক্ষণ না সেটা হয় না। আপনি একই আইটেম দুবার দেখেন। যা আপনি নিশ্চিতভাবে দেখেছিলেন সেটা হারিয়ে গেছে। একটি সারি আপনি ট্যাপ করতে যাচ্ছিলেন হঠাৎ নিচে সরে যায়, এবং আপনি ভুল ডিটেইল পেজে পৌঁছান।
এগুলো ব্যবহারকারীর দেখা যায় এমন বাগ, যদিও আপনার API রেসপন্স আলাদাভাবে “ঠিক” দেখায়। সাধারণ লক্ষণগুলো সহজে চেনা যায়:
- পৃষ্ঠাগুলোর মধ্যে ডুপ্লিকেট আইটেম
- এমন আইটেম মিসিং যা কখনো দেখানো হয়নি
- স্ক্রল করার সময় আইটেম অবস্থান বদলানো
- ইনফিনাইট স্ক্রল যা দ্রুত থেমে যায় বা একই পেজ আবার লোড করে
মোবাইলের উপর এটি আরও খারাপ হয়ে যায়। মানুষ থামে, অ্যাপ বদলায়, কানেক্টিভিটি হারায়, পরে চালিয়ে দেয়। সেই সময়ে নতুন আইটেম আসে, পুরোনোগুলো মুছে ফেলা হয়, এবং কিছু এডিট হয়। যদি আপনার অ্যাপ page 3-এর জন্য অফসেট ব্যবহার করে বারবার অনুরোধ করে, পেজ বাউন্ডারিগুলো ব্যবহারকারীর মাঝখানে বদলে যেতে পারে। ফলাফল: একটি ফিড যা অস্থির এবং অবিশ্বাস্য মনে হয়।
লক্ষ্য সোজা: একবার ব্যবহারকারী সামনে স্ক্রল শুরু করলে, তালিকাটি একটি স্ন্যাপশটের মতো আচরণ করা উচিত। নতুন আইটেম থাকতে পারে, কিন্তু সেগুলো ব্যবহারকারী ইতিমধ্যে পাতানো আইটেমগুলোকে পুনরায় সাজাতে পারবেনা। ব্যবহারকারী একটি মসৃণ, পূর্বানুমেয় ক্রম পাবে।
কোনো পেজিনেশন পদ্ধতি নিখুঁত নয়। বাস্তব সিস্টেমে একসঙ্গে লেখালেখি, এডিট, এবং একাধিক সোর্ট অপশন থাকে। কিন্তু কার্সার পেজিনেশন সাধারণত অফসেট পেজিনেশনের থেকে নিরাপদ, কারণ এটি একটি স্থির ক্রমে নির্দিষ্ট অবস্থান থেকে পেজ করে, পরিবর্তনশীল সারি গণনা থেকে নয়।
এক মিনিটে অফসেট পেজিনেশন
অফসেট পেজিনেশন হচ্ছে “skip N, take M” উপায়। আপনি API-কে বলেন কতগুলো আইটেম স্কিপ করতে (offset) এবং কতগুলো ফিরিয়ে দিতে (limit)। limit=20 থাকলে প্রতি পেজে 20টি আইটেম পাবেন।
ধারণাগতভাবে:
GET /items?limit=20&offset=0(প্রথম পেজ)GET /items?limit=20&offset=20(দ্বিতীয় পেজ)GET /items?limit=20&offset=40(তৃতীয় পেজ)
রেসপন্স সাধারণত আইটেমগুলো এবং পরবর্তী পেজের যথেষ্ট তথ্য দেয়।
{
"items": [
{"id": 101, "title": "..."},
{"id": 100, "title": "..."}
],
"limit": 20,
"offset": 20,
"total": 523
}
এটি জনপ্রিয় কারণ এটি টেবিল, অ্যাডমিন লিস্ট, সার্চ রেজাল্ট, এবং সহজ ফিডের সঙ্গে সুন্দরভাবে মানায়। SQL-এ LIMIT এবং OFFSET দিয়ে এটি বাস্তবে সহজে বাস্তবায়ন করা যায়।
কিন্তু সমস্যাটি হলো লুকানো অনুমান: ডেটাসেটটি ইউজার পেজিং করার সময় স্থির থাকে। বাস্তব অ্যাপে নতুন সারি ইনসার্ট হয়, সারি ডিলিট হয়, এবং সোর্ট কী বদলে যায়। এখানেই “গোপন বাগ” শুরু হয়।
কেন ইনসার্ট বা ডিলিট হলে অফসেট ভেঙে পড়ে
অফসেট পেজিনেশন ধরে নেয় যে অনুরোধগুলোর মধ্যে তালিকাটি স্থির আছে। কিন্তু বাস্তব তালিকাগুলো সরতে পারে। যখন তালিকা সরে যায়, skip 20-এর মত অফসেট আর একই আইটেমগুলোকে নির্দেশ করে না।
ধরুন একটি ফিড created_at desc (নতুনগুলো উপরে), পেজ সাইজ 3।
আপনি offset=0, limit=3 দিয়ে পেজ 1 লোড করেন এবং পান [A, B, C]।
এখন একটি নতুন আইটেম X তৈরি হয় এবং উপরে দেখা যায়। তালিকাটি এখন [X, A, B, C, D, E, F, ...]। আপনি offset=3, limit=3 দিয়ে পেজ 2 লোড করেন। সার্ভার [X, A, B] স্কিপ করে এবং [C, D, E] ফেরত দেয়।
আপনি právě C আবার দেখেছেন (একই আইটেম ডুপ্লিকেট), এবং পরে আপনি একটি আইটেম মিস করবেন কারণ সবকিছু নিচে সরে গেছে।
ডিলিটগুলো ঠিক উল্টো ব্যর্থতা তৈরি করে। শুরুতে [A, B, C, D, E, F, ...] আছে। আপনি পেজ 1 লোড করে দেখলেন [A, B, C]। পেজ 2 নেওয়ার আগেই B ডিলিট হলে তালিকাটি হয় [A, C, D, E, F, ...]। offset=3 দিয়ে পেজ 2 তখন [A, C, D] স্কিপ করে [E, F, G] ফেরত দেয়। D হয়ে যায় একটি গ্যাপ যা আপনি কখনো ফেচ করবেন না।
নিউইস্ট-ফার্স্ট ফিডে ইনসার্টগুলো উপরে হয়, যা ঠিকই পরে থাকা প্রতিটি অফসেটকে সরিয়ে দেয়।
ওয়েব ও মোবাইলের জন্য একটি স্থির তালিকার মানে
"স্থিতিশীল তালিকা" হচ্ছে ব্যবহারকারীরা যা আশা করে: তারা সামনে স্ক্রল করলে আইটেমগুলো ঝাঁপায় না, পুনরাবৃত্তি হয় না, বা অকারণে অদৃশ্য হয় না। এটি সময় ফ্রিজ করার বিষয় নয়, বরং পেজিংকে পূর্বানুমেয় করা।
দুইটি ধারণা প্রায়ই একসাথে মিশে যায়:
- স্থিতিশীল অর্ডারিং: একটি স্পষ্ট সোর্ট নিয়ম আছে (উদাহরণ:
created_atএবং একটি টাই-ব্রেকার যেমনid) যাতে একই ইনপুটে দুইটি রিকোয়েস্টই একই অর্ডার ফেরত দেয়। - স্থিতিশীল পেজিং: একবার ব্যবহারকারী সামনে স্ক্রল শুরু করলে, পরের পেজটি তারা শেষ দেখা আইটেম থেকে চলতে থাকবে, এমনকি নতুন আইটেম যোগ করা বা কিছু আইটেম ডিলিট হলে ও—এটি পুনরাবৃত্তি বা অপ্রত্যাশিত গ্যাপ দেখাবে না।
রিফ্রেশ এবং স্ক্রল-ফরওয়ার্ড আলাদা অ্যাকশন। রিফ্রেশ মানে "এখন কী নতুন আছে তা দেখাও", তাই টপ বদলে যেতে পারে। স্ক্রল-ফরওয়ার্ড মানে "আমি যেখানে ছিলাম সেখানে থেকে চলি", তাই আপনি শিফট হওয়া পেজ বাউন্ডারি থেকে উত্পন্ন পুনরাবৃত্তি বা গ্যাপ দেখতে পাবেন না।
একটি সহজ নিয়ম যা বেশিরভাগ পেজিনেশন বাগ প্রতিরোধ করে: সম্মুখে স্ক্রল করার সময় কখনোই পুনরাবৃত্তি দেখানো উচিত নয়।
কার্সার পেজিনেশন: সহজ ধারণা
কার্সার পেজিনেশন একটি বুকমার্ক ব্যবহার করে তালিকা থেকে এগোয়, পেজ নম্বর না দিয়ে। ক্লায়েন্ট বলে “এখান থেকে চালিয়ে যাও।”
চুক্তি সরল:
- API একটি ব্যাচ আইটেম এবং একটি কার্সার দেয় যা শেষ আইটেমের পরে অবস্থান নির্দেশ করে।
- ক্লায়েন্ট ওই কার্সার পাঠায় পরবর্তী ব্যাচ পেতে।
এটি ইনসার্ট ও ডিলিটকে ভালভাবে সহন করে কারণ কার্সার একটি স্থির ক্রমে কোনো অবস্থানকে অ্যাংকর করে, সারি গণনা থেকে নয়।
অবশ্যই একটি অনিচ্ছেদযোগ্য শর্ত হলো নির্ধারিত ও স্থায়ী সোর্ট অর্ডার থাকা। যদি সোর্ট ডিটারমিনিস্টিক না হয় এবং টাই-ব্রেকার না থাকে, তাহলে কার্সার নির্ভরযোগ্য বুকমার্ক হবে না।
কার্সার ও সোর্ট অর্ডার নির্বাচন
শুরুতে এমন একটি সোর্ট অর্ডার বেছে নিন যা মানুষ কীভাবে তালিকা পড়ে তার সঙ্গে মিল রাখে। ফিড, মেসেজ, এবং অ্যাক্টিভিটি লগ সাধারণত newest-first। ইতিহাসভিত্তিক তালিকা (ইনভয়েস, অডিট লগ) প্রায়ই oldest-first ভাল হয়।
কার্সারকে অবশ্যই ঐ ক্রমে একটি অবস্থান ইউনিকভাবে শনাক্ত করতে হবে। যদি দুইটি আইটেম একই কার্সার ভ্যালু শেয়ার করে, আপনি অবশেষে ডুপ্লিকেট বা গ্যাপ পাবেন।
সাধারণ পছন্দ ও সতর্কতা:
- শুধু
created_at: সহজ, কিন্তু অনিরাপদ যদি অনেক রো একটাই টাইমস্ট্যাম্প শেয়ার করে। - শুধু
id: নিরাপদ যদি ID গুলো মনোটোনিক হয়, তবে হয়ত পণ্য-চাহিদার অর্ডারের সাথে মিলে না। created_at+id: সাধারণত সবচেয়ে ভাল মিশ্রণ (টাইমস্ট্যাম্প পণ্য-কেন্দ্রিক অর্ডার দেয়,idটাই-ব্রেকার হিসেবে)।- প্রধান সোর্ট হিসেবে
updated_at: ইনফিনাইট স্ক্রলের জন্য ঝুঁকিপূর্ণ কারণ এডিট হলে আইটেম পেজগুলোর মধ্যে সরতে পারে।
যদি আপনি একাধিক সোর্ট অপশন প্রদান করেন, প্রতিটি সোর্ট মোডকে আলাদা তালিকা হিসেবে বিবেচনা করুন এবং প্রতিটির জন্য আলাদা কার্সার নিয়ম রাখুন। একটি কার্সার কেবল একটি নির্দিষ্ট অর্ডারিংয়ের জন্যই অর্থবহ।
ধাপে ধাপে: একটি পরিষ্কার কার্সার API আকৃতি
API-ইনটারফেস ছোট রাখা যায়: দুইটি ইনপুট, দুইটি আউটপুট।
1) অনুরোধ: limit + cursor
limit (কতটি আইটেম চান) এবং ঐচ্ছিক cursor (কোথা থেকে চালিয়ে যেতে) পাঠান। যদি কার্সার না থাকে, সার্ভার প্রথম পেজ ফিরিয়ে দেবে।
উদাহরণ অনুরোধ:
GET /api/messages?limit=30&cursor=eyJjcmVhdGVkX2F0IjoiMjAyNi0wMS0xNlQxMDowMDowMFoiLCJpZCI6Ijk4NzYifQ==
2) রেসপন্স: items + next_cursor
আইটেমগুলো এবং একটি next_cursor ফেরত দিন। যদি আর পরবর্তী পেজ না থাকে, next_cursor: null ফেরত দিন। ক্লায়েন্ট কার্সারকে একটি টোকেন হিসেবে আচরণ করবে, সম্পাদনা করবে না।
{
"items": [ {"id":"9876","created_at":"2026-01-16T10:00:00Z","subject":"..."} ],
"next_cursor": "...",
"has_more": true
}
সার্ভার-সাইড লজিক সাধারণ ভাষায়: একটি স্থির অর্ডারে সোর্ট করুন, কার্সার ব্যবহার করে ফিল্টার করুন, তারপর limit প্রয়োগ করুন।
উদাহরণসরূপ, যদি আপনি (created_at DESC, id DESC) অনুযায়ী newest first সোর্ট করেন, কার্সারকে (created_at, id) এ ডিকোড করুন, তারপর সেই কার্সার জোড়ার থেকে কড়া প্রশ্রয়ের শর্ত প্রয়োগ করে সারি সংগ্রহ করুন এবং একই অর্ডার বজায় রেখে limit নিন।
3) কার্সার এনকোডিং: অপ্যাক জিতেছে
কার্সারকে base64 JSON ব্লব হিসেবে এনকোড করা যায় (সহজ) বা সাইন/এনক্রিপট করা টোকেন হিসেবে রাখা যায় (আরো কাজ)। অপ্যাক নিরাপদ কারণ এতে আপনি পরে ইন্টারনাল বদল করলে ক্লায়েন্ট ভাঙবে না।
সঙ্গে কিছু যুক্তিসঙ্গত ডিফল্ট সেট করুন: মোবাইলের জন্য সাধারণত 20–30, ওয়েবের জন্য প্রায় 50, এবং একটি সার্ভার-ম্যাক্স যাতে কোনো বাগধরা ক্লায়েন্ট 10,000 সারি চাইতে না পারে।
ইনসার্ট, ডিলিট, এবং এডিট হ্যান্ডল করা
একটি স্থির ফিড মূলত একটি অঙ্গীকার সম্পর্কে: একবার ব্যবহারকারী সামনে স্ক্রল শুরু করলে, তারা দেখা না করা আইটেমগুলো অন্য কারো দ্বারা তৈরি, মুছে বা সম্পাদিত হওয়ার কারণে লাফাবে না।
কার্সার পেজিনেশনে ইনসার্ট সবচেয়ে সহজ। নতুন রেকর্ডগুলি রিফ্রেশে দেখানো উচিত, ইতিমধ্যে লোড করা পেজগুলোর মধ্যে নয়। যদি আপনি (created_at DESC, id DESC) অর্ডার করুন, নতুন আইটেমগুলো স্বাভাবিকভাবেই প্রথম পেজের আগে থাকবে, তাই আপনার বিদ্যমান কার্সার পুরোনো আইটেমের দিকে চালিয়ে যাবে।
ডিলিটগুলো তালিকাকে পুনরায় সাজাবে না। যদি একটি আইটেম ডিলিট হয়, তখন এটি সহজেই না ফেরত দেওয়া হবে যখন আপনি সেটি ফেচ করতেন। পেজ সাইজ ধরে রাখতে চাইলে দেখা হওয়া limit দৃশ্যমান আইটেম সংগ্রহ না হওয়া পর্যন্ত ফেচ চালিয়ে যান।
এডিট হল যেখানে দলগুলি ভুলবশত বাগ পুনরায় নিয়ে আসে। মূল প্রশ্ন: একটি এডিট কি সোর্ট পজিশন বদলে দিতে পারে?
স্ন্যাপশট আচরণ বা লাইভ আচরণ বেছে নিন
স্ক্রলিং তালিকার জন্য সাধারণত স্ন্যাপশট-স্টাইল আচরণ ভাল: created_at মত একটি অপরিবর্তনীয় কী দিয়ে পেজউইজ করা। এডিট কন্টেন্ট পরিবর্তন করতে পারে, কিন্তু আইটেম নতুন অবস্থানে ঝাঁপাবে না।
লাইভ-ফিড আচরণ যদি edited_at দিয়ে সোর্ট করে; এটার ফলে আইটেমগুলো পেজগুলোর মধ্যে সরতে পারে। যদি আপনি এটি বেছে নেন, তবে তালিকাকে ক্রমাগত পরিবর্তনশীল হিসেবে ধরুন এবং UX-টা রিফ্রেশকে কেন্দ্র করে ডিজাইন করুন।
যখন কার্সার আইটেম আর নেই
কার্সারকে “এই নির্দিষ্ট রোটি খুঁজে পাও”র ওপর নির্ভর করে বানাবেন না। অবস্থান এনকোড করুন, যেমন {created_at, id} যা শেষ ফেরত আইটেমের। তারপর পরবর্তী কুয়েরি মানভিত্তিক হবে:
- অবতরণক্রমে:
WHERE (created_at, id) < (:created_at, :id) - সবসময় একটি টাই-ব্রেকার (
id) অন্তর্ভুক্ত করুন যাতে ডুপ্লিকেট এড়ায় - যদি শেষ আইটেমটি মুছে ফেলা হয়, মানগুলো তখনও কাজ করে
- যদি শেষ আইটেমটি এডিট হয়, তা তখনও কাজ করে যদি আপনার সোর্ট কী অপরিবর্তনীয় হয়
ব্যাকওয়ার্ড পেজিং, রিফ্রেশ, এবং লাফ
ফরওয়ার্ড পেজিং সহজ অংশ। সমস্যা জায়গাগুলো হচ্ছে ব্যাকওয়ার্ড পেজিং, রিফ্রেশ, এবং র্যান্ডম অ্যাক্সেস।
ব্যাকওয়ার্ড পেজিংয়ের জন্য দুইটি পদ্ধতি কাজ করে:
- উভয় দিক ফেরত দিন (
next_cursorপুরোনো আইটেমের জন্য এবংprev_cursorনতুন আইটেমের জন্য) কিন্তু স্ক্রিনে একরকম সোর্ট অর্ডার রাখুন। - একটি কার্সার রাখুন, কিন্তু ব্যবহারকারী উপরের দিকে স্ক্রল করলে রিভার্সড সোর্ট অনুরোধ করুন।
র্যান্ডম লাফ কার্সারের সঙ্গে কঠিন কারণ “পেজ 20” এর একটি স্থির অর্থ থাকে না যখন তালিকা পরিবর্তিত হয়। যদি সত্যিই লাফ দরকার হয়, একটি অ্যাঙ্কারের দিকে লাফ দিন—যেমন “এই টাইমস্ট্যাম্পের চারপাশে” বা “এই মেসেজ id থেকে শুরু করে” — পেজ ইনডেক্স নয়।
মোবাইলে ক্যাশিং গুরুত্বপূর্ণ। প্রতিটি লিস্ট স্টেট (কোয়েরি + ফিল্টার + সোর্ট) অনুযায়ী কার্সার সংরক্ষণ করুন, এবং প্রতিটি ট্যাব/ভিউকে আলাদা তালিকা হিসেবে আচরণ করুন। এতে “ট্যাব বদলে দিলে সবকিছু এলোমেলো হয়ে যায়” সমস্যা রোধ করা যায়।
সাধারণ ভুল যা গোপন বাগ তৈরি করে
অধিকাংশ কার্সার পেজিনেশন ইস্যু ডেটাবেস-সম্পর্কিত নয়। এগুলো ছোট অসামঞ্জস্য থেকে আসে যা কেবল বাস্তব ট্র্যাফিকে প্রকাশ পায়।
সবচেয়ে বড় ভুলগুলো:
- একক নয় এমন কার্সার ব্যবহার করা (উদাহরণ: শুধু
created_at) ফলে টাই ঘটলে ডুপ্লিকেট বা মিসিং আইটেম হয়। - এমন
next_cursorফেরত দেওয়া যা প্রকৃতপক্ষে শেষ ফেরত দেওয়া রো-এর সঙ্গে মিল নেই। - অনুরোধগুলোর মধ্যে ফিল্টার বা সোর্ট অর্ডার বদলানো।
- একই এন্ডপয়েন্টে অফসেট ও কার্সার মিশিয়ে ব্যবহার করা।
আপনি যদি Koder.ai-র মতো প্ল্যাটফর্মে অ্যাপ বানান, এই এজ কেসগুলো দ্রুত দেখা যায় কারণ ওয়েব ও মোবাইল ক্লায়েন্ট প্রায়ই একই এন্ডপয়েন্ট শেয়ার করে। একটি স্পষ্ট কার্সার কনট্রাক্ট এবং নির্ধারিত অর্ডারিং রুল থাকা উভয় ক্লায়েন্টকে সঙ্গত রাখে।
চালু করার আগে দ্রুত চেকলিস্ট
পেজিনেশনকে “করা হয়েছে” বলা কেওয়ালে না, ইনসার্ট, ডিলিট এবং রিট্রাইটের অধীনে আচরণ যাচাই করে নিন।
- সোর্ট স্পষ্ট, ডিটারমিনিস্টিক, এবং একটি টাই-ব্রেকার অন্তর্ভুক্ত
- প্রতিটি অনুরোধে একই ফিল্টার ও সোর্ট ফিল্ড পুনরাবৃত্তি করা হয়
next_cursorশেষ ফেরত রো থেকে নেওয়াlimit-এর একটি নিরাপদ ম্যাক্স এবং ডকুমেন্টেড ডিফল্ট আছে- রিফ্রেশ আচরণ নির্ধারিত (কিভাবে নতুন আইটেম দেখানো হবে)
রিফ্রেশের জন্য একটি পরিচ্ছন্ন নিয়ম নিন: বা ব্যবহারকারীরা পুল-টু-রিফ্রেশ করে টপে নতুন আইটেম আনবে, অথবা আপনি সময়ে সময়ে “আমার প্রথম আইটেমের চেয়ে নতুন কিছু আছে?” চেক করে একটি “New items” বাটন দেখাবেন। ধারাবাহিকতা হল যা তালিকাকে haunted মনে হওয়ার বদলে স্থিতিশীল করে।
একটি বাস্তবসম্মত উদাহরণ: একটি ইনবক্স যা ডিভাইস জুড়ে স্থির থাকে
একটি সাপোর্ট ইনবক্স কল্পনা করুন যা এজেন্টরা ওয়েবে ব্যবহার করে, এবং ম্যানেজার একই ইনবক্স মোবাইলে চেক করে। তালিকা newest-first। প্রত্যাশা স্পষ্ট: যখন তারা সামনে স্ক্রল করে, আইটেমগুলো ঝাঁপে না, পুনরাবৃত্তি হয় না, বা অদৃশ্য হয় না।
অফসেট পেজিংয়ে, একজন এজেন্ট পেজ 1 (আইটেম 1–20) লোড করে, তারপর পেজ 2 (offset=20) তে যায়। তারা পড়ার সময় উপরে দুইটি নতুন মেসেজ আসে। এখন offset=20 তার আগের মানের থেকে ভিন্ন জায়গা নির্দেশ করে। ব্যবহারকারী ডুপ্লিকেট দেখেন বা মিস করেন।
কার্সার পেজিনেশনে, অ্যাপ “এই কার্সারের পরে পরবর্তী 20 আইটেম” চাইবে, যেখানে কার্সারটি ব্যবহারকারী প্রকৃতপক্ষে শেষ দেখা আইটেমের উপর ভিত্তি করে (সাধারণত (created_at, id))। নতুন মেসেজ সারাদিন আসতে পারে, কিন্তু পরবর্তী পেজ তবু শেষ দেখা মেসেজের ঠিক পর থেকেই শুরু হবে।
শিপ করার আগে একটি সহজ পরীক্ষা:
- একটি স্ক্রিপ্ট চালিয়ে পেজ নেওয়ার সময় প্রতি সেকেন্ডে নতুন মেসেজ ইনসার্ট করুন
- মাঝখানে কয়েকটি মেসেজ ডিলিট করুন
- একটি মেসেজ এডিট করুন (তথ্য বদলিয়ে কিন্তু অর্ডারিং ক্ষেত্র না বদলে)
- নিশ্চিত করুন আপনি কখনোই পুনরাবৃত্তি, গ্যাপ বা অপ্রসঙ্গিক অর্ডার পাচ্ছেন না
- যাচাই করুন মোবাইল ও ওয়েব অ্যাপ একই পেজ সীমা দেখায়
প্রোটোটাইপ দ্রুত করতে চাইলে, Koder.ai আপনাকে চ্যাট প্রম্পট থেকে এন্ডপয়েন্ট ও ক্লায়েন্ট ফ্লো স্ক্যাফোল্ড করতে সাহায্য করতে পারে, তারপর Planning Mode প্লাস স্ন্যাপশট ও রোলব্যাক ব্যবহার করে নিরাপদে ইটারেট করুন যখন পেজিনেশন পরিবর্তন টেস্টে আপনাকে আচমকা অপ্রত্যাশিত ফল দেয়।
সাধারণ প্রশ্ন
কেন আমি অফসেট দিয়ে পেজিনেট করার সময় ডুপ্লিকেট বা মিসিং আইটেম পাচ্ছি?
অফসেট পেজিনেশন হল “Nটি সারি স্কিপ করো” পদ্ধতি, তাই যদি নতুন সারি ইনসার্ট হয় বা পুরোনো সারি মুছে ফেলা হয়, সারির গণনা সরতে পারে। একই offset হঠাৎ ভিন্ন আইটেমকে নির্দেশ করতে পারে, ফলে ব্যবহারকারীরা স্ক্রলের মধ্যে পুনরাবৃত্তি বা গ্যাপ দেখতে পান।
কার্সার পেজিনেশন কীভাবে “লিস্ট আমার নিচে বদলে গেছে” সমস্যা প্রতিরোধ করে?
কার্সার পেজিনেশন একটি বুকমার্ক ব্যবহার করে যা “আমি যে শেষ আইটেমটি দেখেছি তার পরে” অবস্থানকে প্রতিনিধিত্ব করে। পরবর্তী অনুরোধ সেই অবস্থান থেকে নির্দিষ্ট ও স্থায়ী ক্রমে চালিয়ে যায়, তাই টপ-এ ইনসার্ট বা মাঝখানে ডিলিট হওয়া আইটেম আপনার পেজ বাউন্ডারি একইভাবে সরায় না।
আমি কী ব্যবহার করব কার্সার হিসেবে: created_at, id, না উভয়?
একটি নির্দিষ্ট এবং ইউনিক টাই-ব্রেকার সহ একটি নির্ধারিত সোর্ট ব্যবহার করুন; সাধারণত (created_at, id) সবচেয়ে ভাল মিশ্রণ। created_at প্রোডাক্ট-ফ্রেন্ডলি অর্ডার দেয়, এবং id প্রতিটি অবস্থানকে ইউনিক করে তোলে যাতে টাইমস্ট্যাম্প সיהם হলে আপনি আইটেম পুনরাবৃত্তি বা স্কিপ না করুন।
আমি কি লাইভ ফিডের জন্য updated_at দিয়ে পেজিনেট করতে পারি?
updated_at-এর উপর সোর্ট করা তখন সমস্যা তৈরি করতে পারে যখন আইটেম এডিট হওয়ার ফলে পেজে তার অবস্থান বদলে যায়—এটি “স্টেবল স্ক্রোল ফরওয়ার্ড” প্রত্যাশাকে ভেঙে দেয়। যদি আপনাকে লাইভ “সর্বশেষ আপডেট” ভিউ দরকার হয়, তাহলে UI-কে রিফ্রেশ ডিজাইন করে পুনরায় অর্ডারিং গ্রহণ করার মতোভাবে বানান।
কার্সার পেজিনেশন জন্য আমার API রেসপন্সে কী থাকা উচিত?
একটি opaque টোকেন next_cursor হিসেবে ফিরিয়ে দেবেন এবং ক্লায়েন্ট সেটি অপরিবর্তিতভাবে ফেরত পাঠাবে। সহজ উপায় হচ্ছে শেষ আইটেমের (created_at, id)-কে base64 JSON ব্লব হিসেবে এনকোড করা, তবে তা একটি অপাক ভ্যালু হিসেবে আচরণ করানোই গুরুত্বপূর্ণ যাতে ভবিষ্যতে ইন্টারনাল বদল করলে ক্লায়েন্ট ব্রেক না করে।
যদি কার্সার দ্বারা প্রদর্শিত আইটেমটি মুছে ফেলা হয় তাহলে কী হবে?
কার্সার ভেলু নির্ভর করে ‘এই সুনির্দিষ্ট রো’ খুঁজে পাওয়ার ওপর তৈরি করবেন না। বরং অবস্থান এনকোড করুন, যেমন শেষ ফেরত দেওয়া আইটেমের {created_at, id}। এরপর পরবর্তি কোয়েরি মানভিত্তিক হবে, না যে রোটি এখন আর আছে কি না- তাতে নয়।
পরবর্তী পৃষ্ঠা ফেচ করার সময় কীভাবে পুনরাবৃত্তি এড়াবো?
কঠোর তুলনা ব্যবহার করুন এবং একটি ইউনিক টাই-ব্রেকার রাখুন, এবং সব সময় next_cursor নেবেন যেটা প্রকৃতপক্ষে শেষ ফেরত দেওয়া রো থেকে নেওয়া হয়েছে। বেশিরভাগ পুনরাবৃত্তি ত্রুটি হয় <= ব্যবহার করার কারণে, টাই-ব্রেকার না রাখার কারণে, বা ভুল রো থেকে next_cursor তৈরির কারণে।
কার্সার পেজিনেশনের সাথে রিফ্রেশ কিভাবে কাজ করা উচিত?
স্পষ্ট একটি নিয়ম বেছে নিন: রিফ্রেশ টপে নতুন আইটেম লোড করে, আর স্ক্রোল-ফরওয়ার্ড বিদ্যমান কার্সার থেকে পুরোনো আইটেমের দিকে চালিয়ে যায়। রিফ্রেশ সেমানটিক্সকে একই কার্সার ফ্লোর সঙ্গে মিশাবেন না, না হলে ব্যবহারকারী রি-অর্ডারিং দেখে লিস্ট অপ্রত্যাশিত মনে করবে।
ব্যবহারকারী ফিল্টার বা সোর্ট পরিবর্তন করলে কি একই কার্সার ব্যবহার করা যাবে?
একটি কার্সার কেবল একটি সুনির্দিষ্ট অর্ডার ও ফিল্টার সেটের জন্যই মান্য। যদি ক্লায়েন্ট সোর্ট মোড, সার্চ কোয়েরি বা ফিল্টার পরিবর্তন করে, তাহলে মাথা ন্যূনশর্ত ছাড়া নতুন পেজিনেশন সেশান শুরু করতে হবে এবং আলাদা লিস্ট স্টেটের জন্য আলাদা কার্সার সংরক্ষণ করতে হবে।
কার্সার দিয়ে কীভাবে আমি নির্দিষ্ট পেজে লাফ বা র্যান্ডম অ্যাক্সেস সাপোর্ট করব?
কার্সার পেজিনেশন ধারাবাহিক ব্রাউজিংয়ের জন্য চমৎকার, তবে “পেজ ২০” ধরনের স্থির লাফের জন্য উপযুক্ত নয় কারণ ডেটাসেট পরিবর্তিত হতে পারে। যদি লাফ দরকার হয়, তাহলে একটি অ্যাঙ্কর-এ লাফ দিন—যেমন “এই টাইমস্ট্যাম্পের চারপাশে” বা “এই id-এর পরে শুরু করে”—তারপর সেখান থেকে কার্সার দিয়ে পেজিনেট করুন।