MongoDB Aggregation Stages

What you’ll learn
- What an aggregation pipeline is and how stages chain together.
- Which stage to use for filtering, reshaping, grouping, joining, sorting, and writing output.
- A suggested learning path from
$matchthrough$lookup. - How to read and design multi-stage pipelines for real reports.
- Links to every stage tutorial on CodeToFun (32 stages).
Prerequisites
Basic MongoDB familiarity: collections, documents, find(), and running commands in mongosh. Helpful background: installation and understanding BSON field paths like "$amount".
- Collections & documents: pipelines read from one collection (or a view) and output a stream of documents.
- Query filters:
$matchreuses find-style operators—know$gt,$in, and$andbasics. - Accumulators:
$grouppairs with operators like$sum—see the accumulators hub when you reach grouping. - Compass optional: the aggregation tab visualizes each stage’s output—great for debugging.
Key concepts
Think of a pipeline as an assembly line: each stage is a machine that receives documents, transforms them, and hands them to the next stage. The final stage’s output is what aggregate() returns.
Ordered stages
Stages run top to bottom in the array you pass to aggregate().
Document stream
Each stage consumes and produces a stream of documents (except writers like $out).
Composable
Mix stages freely—filter, join, group, sort, and paginate in one query.
Filter early
Place $match as early as possible so later stages process fewer documents.
Overview
Aggregation stages power analytics in MongoDB: sales by region, joined order lines, paginated leaderboards, geo-radius searches, and materialized summary collections. Most apps need only a handful of stages day to day; the full catalog covers specialized joins, bucketing, Atlas Search, and server diagnostics.
Filter & reshape
$match, $project, $addFields, $unset.
Summarize
$group, $count, $bucket, $facet.
Join & expand
$lookup, $unwind, $graphLookup.
⚖️ Picking the right stage
Match the task to the stage family before you write a pipeline.
| Goal | Start with | Notes |
|---|---|---|
| Keep only some documents | $match | Same filter syntax as find(); put early for index use. |
| Rename or hide fields | $project | Inclusion mode keeps listed fields; exclusion removes them. |
| Add a calculated column | $addFields | Keeps all existing fields; alias $set in 4.2+. |
| Totals per category | $group | Pair with accumulators from the accumulators hub. |
| Join another collection | $lookup | Often followed by $unwind to flatten arrays. |
| Top 10 by score | $sort + $limit | Add $skip for page 2, page 3, etc. |
| Save results to a collection | $out or $merge | $merge supports upserts; $out replaces the target. |
A typical reporting pipeline
Filter completed orders, join customer names, compute line totals, group revenue by region, and return the top regions—five stages, one query.
db.orders.aggregate([
{ $match: { status: "completed", orderDate: { $gte: ISODate("2025-01-01") } } },
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
},
{ $unwind: "$customer" },
{
$addFields: {
lineTotal: { $multiply: ["$quantity", "$unitPrice"] }
}
},
{
$group: {
_id: "$customer.region",
revenue: { $sum: "$lineTotal" },
orders: { $sum: 1 }
}
},
{ $sort: { revenue: -1 } },
{ $limit: 5 }
]); Suggested learning path
Follow this order if you are new to aggregation pipelines. Each link opens a dedicated tutorial with examples and FAQs.
- Filter:
$match— shrink the dataset first. - Shape:
$projectand$addFields— pick and compute columns. - Summarize:
$groupwith$sumand$avg. - Order & paginate:
$sort,$limit,$skip. - Join:
$lookup+$unwindfor related data. - Multi-view queries:
$facetand$sortByCount. - Write output:
$mergeor$outfor materialized reports.
The sidebar tutorial order walks every stage alphabetically by slug, starting with $addFields.
Stage index
Every tutorial lives at /mongodb/stages/{slug}. Multi-word stage names use kebab-case slugs (for example add-fields, sort-by-count, graph-lookup).
Filter
| Stage | What it does |
|---|---|
$match | Filter documents with the same query syntax as find()—equality, ranges, $in, $regex, and $expr. |
Transform & reshape
| Stage | What it does |
|---|---|
$project | Include, exclude, or compute fields; reshape each document as it passes through. |
$addFields | Add computed fields while keeping existing ones (alias: $set). |
$set | MongoDB 4.2+ alias for $addFields—same syntax, additive field updates. |
$unset | Remove one or more fields from every document in the stream. |
$replaceRoot | Promote a sub-document or expression result to become the new root document. |
$replaceWith | Replace the entire document with an expression result (alias for $replaceRoot in many cases). |
$redact | Conditionally prune, mask, or keep fields for field-level security policies. |
Group, count & bucket
| Stage | What it does |
|---|---|
$group | Bucket documents by _id and run accumulators ($sum, $avg, $push, etc.) per group. |
$count | Return a single document { count: N } with the number of documents seen so far. |
$sortByCount | Group by a field value and sort buckets by descending count—great for top-N frequency lists. |
$bucket | Place numeric values into manually defined boundary buckets (histogram-style). |
$bucketAuto | Automatically choose bucket boundaries from data distribution and a target count. |
$facet | Run multiple sub-pipelines on the same input and return named result arrays (dashboards in one query). |
Sort & paginate
| Stage | What it does |
|---|---|
$sort | Order documents by one or more fields; required before ranked accumulators or stable $first/$last. |
$skip | Drop the first N documents—use with $sort and $limit for pagination offsets. |
$limit | Pass only the first N documents to the next stage. |
$sample | Randomly select up to N documents—useful for previews and approximate analytics. |
Join & graph traversal
| Stage | What it does |
|---|---|
$lookup | Left-outer join another collection (SQL-style or correlated sub-pipeline form). |
$unwind | Deconstruct an array field so each element becomes its own document. |
$graphLookup | Recursively traverse a self-referencing collection (org charts, comment threads). |
Geo & search
| Stage | What it does |
|---|---|
$geoNear | Find documents near a point or line; must be first stage when used; outputs distance. |
$search | Atlas Search stage for full-text, fuzzy, and faceted search on Atlas clusters. |
Write output
| Stage | What it does |
|---|---|
$out | Write pipeline results to a collection, replacing or creating it atomically. |
$merge | Upsert pipeline output into an existing collection with flexible when-matched rules. |
Diagnostics & admin
| Stage | What it does |
|---|---|
$collStats | Return collection storage and index statistics for the current namespace. |
$indexStats | Report index usage metrics—helpful when tuning slow aggregations. |
$currentOp | Inspect in-flight operations on the mongod instance (admin diagnostics). |
$planCacheStats | Expose plan cache entries for query plan analysis. |
$changeStream | Open a change stream cursor on the aggregation (replica set / sharded cluster). |
$listLocalSessions | List sessions on the connected mongod (MongoDB 3.6+). |
$listSessions | List all sessions across the deployment via mongos or replica set primary. |
Pitfalls to avoid
Late filtering wastes work
Every stage after an early $match processes fewer documents. Filtering after $lookup or $unwind can explode row counts first.
Array explosion
$unwind multiplies documents—one per array element. Large arrays joined via $lookup can produce huge intermediate streams.
Missing _id
_id is required in $group. Use _id: null for a single global summary bucket.
Must be first
When you use $geoNear, it must be the first stage in the pipeline (after any optional $documents on views).
❓ FAQ
Summary
- Scope: 32 stage tutorials covering filter, transform, group, join, geo, write, and diagnostic stages.
- Pattern: pipelines are ordered arrays; each stage transforms a document stream.
- Next step: open MongoDB $addFields Stage or jump to
$matchin the learning path.
MongoDB can often push an early $match and sometimes $sort + $limit to the collection scan using indexes—the aggregation planner treats them like optimized find queries when possible. See the official pipeline optimization guide.
9 people found this page helpful
