Chapter 14: MongoDB Aggregation $limit
1. What does $limit actually do? (Plain teacher language)
$limit tells the aggregation pipeline:
“After the previous stages have done their work, only pass the first N documents to the next stage (or to the final output). Discard everything after that.”
- It operates on the stream of documents coming from the previous stage.
- It does NOT look at the content — it just counts and stops.
- Very cheap & fast operation (especially when combined smartly with $sort).
- Takes one argument: a positive 64-bit integer (so max is huge: 9,223,372,036,854,775,807 — practically unlimited for real use).
Syntax (super simple):
|
0 1 2 3 4 5 6 |
{ $limit: <positive integer> } |
Example:
|
0 1 2 3 4 5 6 7 8 |
{ $limit: 5 } // keep only first 5 documents that reach this stage { $limit: 100 } // top 100 { $limit: 1 } // just the first one (like findOne() but in pipeline) |
2. Where $limit usually lives in a pipeline (very important!)
Typical order — notice $limit is almost always near the end:
- $match → filter what we care about (early = good for performance)
- $unwind (if needed)
- $group → summarize
- $sort → order the groups/results
- $limit → take only top N
- $project → shape final output
Why near the end? Because you usually want to limit after sorting (top 10 highest rated, most recent, etc.).
3. Hands-on Examples – Let’s Use Our Movie Collection Again
Assume we have the movies collection from earlier (RRR, Kalki, Pushpa 2, Oppenheimer…).
|
0 1 2 3 4 5 6 |
use movieAnalytics2026 |
Example 1: Simplest — Just limit everything to 2 documents
|
0 1 2 3 4 5 6 7 8 |
db.movies.aggregate([ { $limit: 2 } ]) |
→ Returns only the first 2 documents in natural order (insertion or disk order — not useful alone).
Example 2: Most common real pattern — Top 3 highest rated movies
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
db.movies.aggregate([ { $match: { rating: { $exists: true } } }, // optional filter { $sort: { rating: -1 } }, // highest rating first { $limit: 3 }, // only top 3 { $project: { title: 1, rating: 1, year: 1, _id: 0 }} ]) |
Expected output (something like):
|
0 1 2 3 4 5 6 7 8 |
{ "title": "Pushpa 2", "rating": 8.5, "year": 2025 } { "title": "Oppenheimer", "rating": 8.4, "year": 2023 } { "title": "RRR", "rating": 8.1, "year": 2022 } |
Example 3: Pagination (very common in apps — page 2 of 10 items)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const page = 2; const pageSize = 10; db.movies.aggregate([ { $sort: { releaseDate: -1 } }, // newest first { $skip: (page - 1) * pageSize }, // skip previous pages { $limit: pageSize }, // take only this page { $project: { title: 1, year: 1 } } ]) |
→ Classic skip + limit for infinite scroll / pagination.
Teacher tip: $skip + $limit is okay for small pages, but for large offsets (page 1000) → performance drops. In real apps use indexed range queries or search indexes instead.
Example 4: Top N per group (combine with $group)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
db.movies.aggregate([ { $unwind: "$genres" }, { $group: { _id: "$genres", titles: { $push: "$title" }, count: { $sum: 1 } }}, { $sort: { count: -1 } }, // most popular genres first { $limit: 3 }, // only top 3 genres { $project: { genre: "$_id", movieCount: "$count", exampleMovies: { $slice: ["$titles", 5] }, // show first 5 movies per genre _id: 0 }} ]) |
→ Shows only the 3 most common genres + some example movies.
4. Important Behaviors & Gotchas (Listen carefully!)
| Point | Explanation | Recommendation / Gotcha Fix |
|---|---|---|
| Argument must be positive integer | { $limit: “5” } → error! Must be number: { $limit: 5 } | Always use number literal or parseInt() in code |
| Max value | 64-bit positive integer (huge) — no practical limit | — |
| $limit before $sort | Limits before sorting → usually wrong (you get random top N) | Almost always $sort → $limit |
| $sort immediately before $limit | MongoDB optimization: only keeps top N in memory during sort (huge perf win) | Use this pattern for “top K” queries |
| $limit after $group | Limits number of groups (very common) | Perfect for “top 10 categories” |
| No $limit at all | Returns all documents (up to 16 MB batch limit per cursor.next()) | Add $limit when you don’t need everything |
| $limit: 0 | Invalid — must be positive (>0) | Error thrown |
5. Quick Summary Table – Your $limit Cheat Sheet
| Goal | Typical Pipeline Ending | Why $limit here? |
|---|---|---|
| Top 10 highest rated | … → $sort: { rating: -1 } → $limit: 10 | Get leaders only |
| Pagination (page 3, 20 per page) | … → $skip: 40 → $limit: 20 | Show subset of results |
| Top 5 categories | … → $group → $sort: { count: -1 } → $limit: 5 | Limit summarized groups |
| Just see sample data | { $limit: 5 } at beginning | Quick preview during development |
| Memory optimization on large sort | $sort → $limit | MongoDB uses “top K sort” optimization |
6. Mini Exercise – Try Right Now in mongosh!
- Get the top 2 highest rated movies (sort + limit)
- Show only first 3 genres by popularity (unwind → group → sort → limit)
- Implement simple pagination: skip 2 documents, limit 3
- Compare: what happens if you put $limit: 2before$sort vs after?
Understood beta? $limit looks boring… but when paired with $sort, $group, $match — it becomes your best friend for fast, focused, user-friendly results.
Next class — what shall we conquer?
- $skip deep dive + pagination best practices?
- $sort + $limit memory optimization details?
- How to do “top N per group” properly (very common interview question)?
- Or start building a small “Movie Dashboard” pipeline combining everything?
Tell me — class is still in session! 🚀❤️
Any doubt about $limit? Ask freely — we’ll debug it together 😄
