Limiting MongoDB query results with .limit(n) caps how many documents a single query returns, protecting your Node.js server from memory spikes and slow API responses. Combining .sort(), .skip(), and .limit() builds clean page-number pagination, while cursor (_id > lastId) pagination keeps large collections fast at any depth.
.skip() + .limit())Always validate page and pageSize on the server, clamp pageSize (for example, max 100), and include .sort() before .skip() and .limit().
async function getLessonsPage(lessonsCollection, page = 1, pageSize = 15) {
const safePage = Math.max(1, Number(page) || 1);
const safeSize = Math.min(100, Math.max(1, Number(pageSize) || 15));
const skip = (safePage - 1) * safeSize;
const [items, total] = await Promise.all([
lessonsCollection
.find({ isActive: true })
.sort({ order: 1, _id: 1 })
.skip(skip)
.limit(safeSize)
.toArray(),
lessonsCollection.countDocuments({ isActive: true }),
]);
return {
items,
page: safePage,
totalPages: Math.ceil(total / safeSize),
total,
};
}
As collections grow to hundreds of thousands of documents, .skip(50000) becomes slow because MongoDB still walks and discards all 50,000 skipped entries. For infinite-scroll feeds or large exports, filter by { _id: { $gt: new ObjectId(lastSeenId) } } with .sort({ _id: 1 }).limit(20) so MongoDB jumps straight to the next slice using the _id index.
.skip() and .limit() without .sort(): Without a deterministic sort order, MongoDB can return documents in shifting order, causing duplicates or skipped rows between pages.?limit=100000: Unbounded limits can freeze your Node process and exhaust MongoDB bandwidth. Always enforce a strict server-side cap.cursor.count(): cursor.count() was removed in modern MongoDB drivers; use collection.countDocuments(filter) instead..limit(0) in MongoDB?In MongoDB, .limit(0) means no limit at all (return every matching document)! Always clamp safeSize >= 1 so a query param ?limit=0 never dumps the whole collection.
Yes. An aggregation pipeline using $facet (items branch with $skip/$limit and meta branch with $count) can return both in one database round-trip.
estimatedDocumentCount() faster than countDocuments()?Yes, estimatedDocumentCount() reads collection metadata in constant time without scanning indexes, though it does not accept a filter.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.