Penomboran Berhalaman Keyset Dengan Pertanyaan Julat
Pelajar akan membina penomboran berhalaman berasaskan kursor menggunakan penapis julat pada _id atau medan cap masa, dengan mencapai prestasi halaman O(log n) yang konsisten.
Penomboran Berhalaman Keyset Dengan Pertanyaan Julat ialah pelajaran MongoDB Academy percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran MongoDB Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus MongoDB Academy merangkumi sejumlah 4 pelajaran.
Apakah Penomboran Set Kunci?
Penomboran set kunci—juga dipanggil penomboran kursor—mengelakkan skip() sepenuhnya dengan menggunakan pertanyaan julat pada kunci isihan. Daripada memberitahu MongoDB “langkau N dokumen pertama”, anda memberitahunya “berikan dokumen yang kunci isihannya lebih besar daripada nilai terakhir yang saya lihat”. Kaedah ini sentiasa mempunyai kerumitan O(log n) kerana menggunakan imbasan julat indeks, tanpa mengira sejauh mana kedudukan anda dalam set hasil.
Konsep Teras: Penapis Julat sebagai Kursor
Selepas mendapatkan halaman pertama, anda mengingati nilai kunci isihan bagi dokumen terakhir yang dikembalikan. Untuk halaman seterusnya, anda menapis dokumen yang kunci isihannya lebih besar daripada nilai yang diingati (atau lebih kecil bagi susunan menurun). Penapis ini, apabila digabungkan dengan indeks, memberikan MongoDB titik permulaan yang tepat—tiada langkauan diperlukan.
// First page — no cursor needed
const page1 = await db.collection('posts')
.find({ isPublished: true })
.sort({ createdAt: -1, _id: -1 })
.limit(20)
.toArray();
// Remember the last document's sort keys
const lastCreatedAt = page1[page1.length - 1].createdAt;
const lastId = page1[page1.length - 1]._id;Mendapatkan Halaman Seterusnya dengan Pertanyaan Julat
Gunakan nilai kunci isihan yang diingati dalam syarat $lt (atau $gt bagi susunan menaik) untuk pertanyaan halaman seterusnya. skip() tidak diperlukan—syarat julat menavigasi indeks terus ke kedudukan permulaan yang betul. MongoDB mendapatkan dokumen limit bermula dari titik tersebut.
// Next page: posts older than the last one seen
// Descending by createdAt means 'older' = $lt
const page2 = await db.collection('posts')
.find({
isPublished: true,
$or: [
{ createdAt: { $lt: lastCreatedAt } },
{ createdAt: lastCreatedAt, _id: { $lt: lastId } } // tiebreaker
]
})
.sort({ createdAt: -1, _id: -1 })
.limit(20)
.toArray();Mengapa Sertakan _id sebagai Pemecah Seri?
Beberapa dokumen mungkin mempunyai cap masa createdAt yang sama (contohnya, banyak item disisipkan dalam saat yang sama). Tanpa pemecah seri, sempadan julat menjadi samar dan anda mungkin melangkau atau menduplikasi dokumen pada sempadan tersebut. Menambahkan _id sebagai medan isihan sekunder dan menyertakannya dalam syarat julat menjadikan kursor unik dan berketentuan—tiada dokumen boleh mempunyai pasangan (createdAt, _id) yang sama.
// Compound index to support the keyset query
db.posts.createIndex({ createdAt: -1, _id: -1 });
// This index covers both the sort and the range filterPenomboran Set Kunci pada _id Sahaja
Jika anda mengisih semata-mata mengikut _id (susunan sisipan lalai), penomboran set kunci berada dalam bentuk yang paling ringkas. _id sentiasa unik dan telah diindeks. Setiap halaman mengembalikan dokumen yang _id-nya lebih besar daripada nilai terakhir yang dilihat. Kaedah ini berfungsi dengan sempurna untuk pertanyaan berbentuk suapan apabila susunan sisipan ialah isihan semula jadi.
// First page
const page1 = await db.collection('events')
.find({})
.sort({ _id: 1 })
.limit(50)
.toArray();
const lastId = page1[page1.length - 1]._id;
// Next page — range filter on _id
const page2 = await db.collection('events')
.find({ _id: { $gt: lastId } })
.sort({ _id: 1 })
.limit(50)
.toArray();Mengekod Kursor untuk Respons API
Klien API tidak sepatutnya perlu mengetahui format kursor dalaman. Kodkan kursor sebagai rentetan Base64 atau JWT yang boleh dinyahkod oleh pelayan pada permintaan seterusnya. Ini menyembunyikan butiran pelaksanaan (sama ada anda menggunakan createdAt, _id atau kunci gabungan) daripada klien dan membolehkan anda mengubah format kursor tanpa merosakkan kontrak API.
// Encode cursor
function encodeCursor(doc) {
return Buffer.from(JSON.stringify({ createdAt: doc.createdAt, _id: doc._id })).toString('base64');
}
// Decode cursor
function decodeCursor(token) {
return JSON.parse(Buffer.from(token, 'base64').toString('utf-8'));
}
// API response
const nextCursor = page.length === PAGE_SIZE ? encodeCursor(page[page.length - 1]) : null;
res.json({ data: page, nextCursor });Penomboran Set Kunci dalam Pengendali Express
Pengendali penomboran set kunci yang lengkap menyahkod kursor masuk (jika diberikan), membina penapis julat, menjalankan pertanyaan, mengekod kursor seterusnya dan mengembalikan respons. Jika tiada kursor seterusnya untuk dikembalikan (halaman itu lebih kecil daripada saiz halaman), klien mengetahui bahawa halaman terakhir telah dicapai.
async function listPosts(req, res) {
const limit = 20;
let filter = { isPublished: true };
if (req.query.cursor) {
const { createdAt, _id } = decodeCursor(req.query.cursor);
filter['$or'] = [
{ createdAt: { $lt: new Date(createdAt) } },
{ createdAt: new Date(createdAt), _id: { $lt: _id } }
];
}
const posts = await Post.find(filter).sort({ createdAt: -1, _id: -1 }).limit(limit).lean();
const nextCursor = posts.length === limit ? encodeCursor(posts[posts.length - 1]) : null;
res.json({ data: posts, nextCursor });
}Set Kunci Berbanding Anjakan: Perbandingan Prestasi
Bayangkan sebuah collection dengan 1,000,000 posts. Penomboran beranjak ke halaman 1000 (20 item setiap halaman) melaksanakan skip(19980)—MongoDB melintasi 19,980 entri indeks. Penomboran set kunci menggunakan penapis julat: { createdAt: { $lt: someDate } }—MongoDB melakukan carian binari pada indeks untuk mencari titik permulaan dan mengimbas tepat 20 entri. Perbezaannya pada skala besar: milisaat berbanding saat.
Batasan Penomboran Set Kunci
Paginasi keyset mempunyai dua batasan penting: (1) anda tidak boleh melompat ke nombor halaman sewenang-wenangnya—anda hanya boleh bergerak ke hadapan atau ke belakang satu halaman pada satu masa; (2) medan isihan mestilah menjadi sebahagian daripada kursor, jadi pengisihan mengikut medan yang tidak unik dan tidak diindeks memerlukan pemilihan penentu seri yang teliti. Pertukaran ini menjadikan paginasi keyset tidak sesuai untuk aplikasi yang memerlukan navigasi berdasarkan nombor halaman, tetapi ia merupakan pilihan yang tepat untuk tatal tanpa henti dan corak kursor API.
Paginasi Keyset Dua Hala
Untuk menyokong navigasi ke 'halaman seterusnya' dan 'halaman sebelumnya', simpan kedua-dua kursor untuk dokumen pertama dan kursor untuk dokumen terakhir pada setiap halaman. Gunakan $gt dengan kursor dokumen pertama untuk bergerak ke belakang. Terbalikkan arah isihan untuk pertanyaan ke belakang, kemudian terbalikkan semula hasilnya sebelum mengembalikannya.
// Previous page — documents newer than the first item on the current page
const prevPage = await db.collection('posts')
.find({
isPublished: true,
createdAt: { $gt: firstDocCreatedAt }
})
.sort({ createdAt: 1, _id: 1 }) // reverse sort for previous page
.limit(20)
.toArray();
prevPage.reverse(); // flip back to descending display orderReka Bentuk Indeks untuk Paginasi Keyset
Indeks kompaun untuk pertanyaan paginasi keyset hendaklah merangkumi: medan penapis dahulu (syarat kesamaan), kemudian medan isihan. Contohnya, jika anda menapis mengikut isPublished dan mengisih mengikut createdAt DESC, _id DESC, indeks yang ideal ialah { isPublished: 1, createdAt: -1, _id: -1 }. Indeks ini meliputi penapis kesamaan dan isihan julat tanpa sebarang operasi dalam ingatan.
// Ideal covering index for keyset pagination on posts
db.posts.createIndex({ isPublished: 1, createdAt: -1, _id: -1 });
// Verify with explain — expect IXSCAN, no SORT stage
db.posts.find({ isPublished: true, createdAt: { $lt: new Date() } })
.sort({ createdAt: -1, _id: -1 })
.limit(20)
.explain('executionStats');Semakan Pantas
Uji pemahaman anda tentang konsep MongoDB dan pangkalan data NoSQL daripada pelajaran ini.
Rumusan Pelajaran
Dalam pelajaran ini, anda telah mempelajari bahawa: paginasi keyset menggunakan penapis julat pada kunci isihan terakhir yang dilihat dan bukannya skip(), ini mencapai prestasi O(log n) tanpa mengira kedalaman halaman, dan menyertakan _id sebagai penentu seri menghalang dokumen pendua atau dokumen yang hilang pada sempadan isihan. Seterusnya, kita akan berlatih menggabungkan sort, skip, limit dan projection menjadi satu rantaian pertanyaan lengkap.
Pelajari JavaScript dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 30
- Pelajaran
- 120
Soalan Lazim
Adakah pelajaran “Penomboran Berhalaman Keyset Dengan Pertanyaan Julat” percuma?
Ya — teks penuh “Penomboran Berhalaman Keyset Dengan Pertanyaan Julat” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus MongoDB Academy, tingkat taraf kepada CoddyKit PRO. Kursus MongoDB Academy merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Penomboran Berhalaman Keyset Dengan Pertanyaan Julat”?
Pelajar akan membina penomboran berhalaman berasaskan kursor menggunakan penapis julat pada _id atau medan cap masa, dengan mencapai prestasi halaman O(log n) yang konsisten. Anda berlatih MongoDB Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan MongoDB Academy?
Tiada pengalaman terdahulu diperlukan. Pembelajaran MongoDB Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.
Berapa lamakah pelajaran “Penomboran Berhalaman Keyset Dengan Pertanyaan Julat” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran MongoDB Academy ini?
Ya. Setiap pelajaran MongoDB Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Pengisihan Dengan sort() dan Berbilang Kekunci
- Skip dan Limit: Penomboran Berhalaman Berasaskan Offset
- Penomboran Berhalaman Keyset Dengan Pertanyaan Julat
- Menggabungkan Pengisihan, Skip, Limit dan Unjuran