MongoDB Cursor Pagination With Mongoose
Paginate large MongoDB collections with stable cursor queries on indexed compound sort keys, avoiding skipped documents on offset paging.
Code
import mongoose from 'mongoose';
const EventSchema = new mongoose.Schema(
{ userId: Number, kind: String, at: Date },
{ timestamps: false },
);
EventSchema.index({ userId: 1, at: -1, _id: -1 });
const Event = mongoose.model('Event', EventSchema);
async function page(userId, cursor = null, limit = 20) {
const filter = { userId };
if (cursor) {
const [at, id] = cursor.split('|');
filter.$or = [
{ at: { $lt: new Date(at) } },
{ at: new Date(at), _id: { $lt: new mongoose.Types.ObjectId(id) } },
];
}
const docs = await Event.find(filter)
.sort({ at: -1, _id: -1 })
.limit(limit + 1);
const hasMore = docs.length > limit;
const items = hasMore ? docs.slice(0, limit) : docs;
const last = items[items.length - 1];
return {
items,
nextCursor: hasMore && last ? `${last.at.toISOString()}|${last._id}` : null,
};
}
const first = await page(42);
const second = await page(42, first.nextCursor);
console.log('page sizes:', first.items.length, second.items.length);Report a problem with this exampleOpens a pre-filled issue on GitHub.