MongoDB Aggregation Stages

Beginner
⏱️ 16 min read
📚 Updated: Jul 2026
🎯 32 Tutorials
Aggregation

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 $match through $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: $match reuses find-style operators—know $gt, $in, and $and basics.
  • Accumulators: $group pairs 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.

GoalStart withNotes
Keep only some documents$matchSame filter syntax as find(); put early for index use.
Rename or hide fields$projectInclusion mode keeps listed fields; exclusion removes them.
Add a calculated column$addFieldsKeeps all existing fields; alias $set in 4.2+.
Totals per category$groupPair with accumulators from the accumulators hub.
Join another collection$lookupOften followed by $unwind to flatten arrays.
Top 10 by score$sort + $limitAdd $skip for page 2, page 3, etc.
Save results to a collection$out or $merge$merge supports upserts; $out replaces the target.
1

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.

mongosh
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.

  1. Filter: $match — shrink the dataset first.
  2. Shape: $project and $addFields — pick and compute columns.
  3. Summarize: $group with $sum and $avg.
  4. Order & paginate: $sort, $limit, $skip.
  5. Join: $lookup + $unwind for related data.
  6. Multi-view queries: $facet and $sortByCount.
  7. Write output: $merge or $out for 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

StageWhat it does
$matchFilter documents with the same query syntax as find()—equality, ranges, $in, $regex, and $expr.

Transform & reshape

StageWhat it does
$projectInclude, exclude, or compute fields; reshape each document as it passes through.
$addFieldsAdd computed fields while keeping existing ones (alias: $set).
$setMongoDB 4.2+ alias for $addFields—same syntax, additive field updates.
$unsetRemove one or more fields from every document in the stream.
$replaceRootPromote a sub-document or expression result to become the new root document.
$replaceWithReplace the entire document with an expression result (alias for $replaceRoot in many cases).
$redactConditionally prune, mask, or keep fields for field-level security policies.

Group, count & bucket

StageWhat it does
$groupBucket documents by _id and run accumulators ($sum, $avg, $push, etc.) per group.
$countReturn a single document { count: N } with the number of documents seen so far.
$sortByCountGroup by a field value and sort buckets by descending count—great for top-N frequency lists.
$bucketPlace numeric values into manually defined boundary buckets (histogram-style).
$bucketAutoAutomatically choose bucket boundaries from data distribution and a target count.
$facetRun multiple sub-pipelines on the same input and return named result arrays (dashboards in one query).

Sort & paginate

StageWhat it does
$sortOrder documents by one or more fields; required before ranked accumulators or stable $first/$last.
$skipDrop the first N documents—use with $sort and $limit for pagination offsets.
$limitPass only the first N documents to the next stage.
$sampleRandomly select up to N documents—useful for previews and approximate analytics.

Join & graph traversal

StageWhat it does
$lookupLeft-outer join another collection (SQL-style or correlated sub-pipeline form).
$unwindDeconstruct an array field so each element becomes its own document.
$graphLookupRecursively traverse a self-referencing collection (org charts, comment threads).

Geo & search

StageWhat it does
$geoNearFind documents near a point or line; must be first stage when used; outputs distance.
$searchAtlas Search stage for full-text, fuzzy, and faceted search on Atlas clusters.

Write output

StageWhat it does
$outWrite pipeline results to a collection, replacing or creating it atomically.
$mergeUpsert pipeline output into an existing collection with flexible when-matched rules.

Diagnostics & admin

StageWhat it does
$collStatsReturn collection storage and index statistics for the current namespace.
$indexStatsReport index usage metrics—helpful when tuning slow aggregations.
$currentOpInspect in-flight operations on the mongod instance (admin diagnostics).
$planCacheStatsExpose plan cache entries for query plan analysis.
$changeStreamOpen a change stream cursor on the aggregation (replica set / sharded cluster).
$listLocalSessionsList sessions on the connected mongod (MongoDB 3.6+).
$listSessionsList all sessions across the deployment via mongos or replica set primary.

Pitfalls to avoid

$match

Late filtering wastes work

Every stage after an early $match processes fewer documents. Filtering after $lookup or $unwind can explode row counts first.

$unwind

Array explosion

$unwind multiplies documents—one per array element. Large arrays joined via $lookup can produce huge intermediate streams.

$group

Missing _id

_id is required in $group. Use _id: null for a single global summary bucket.

$geoNear

Must be first

When you use $geoNear, it must be the first stage in the pipeline (after any optional $documents on views).

❓ FAQ

A stage is one step in an aggregation pipeline. Each stage receives documents from the previous stage, transforms or filters them, and passes the result forward. Stages run in array order inside db.collection.aggregate([ ... ]).
Start with $match to filter, $project to shape fields, $group to summarize, $sort to order results, then $lookup and $unwind for joins. That combination covers most reporting queries.
Yes. $match early reduces data volume and can use indexes. $sort before $group affects $first and $last. $geoNear must be first when present. $out and $merge are typically last because they write results.
$project reshapes output—you choose which fields survive. $addFields keeps all existing fields and adds or overwrites specific ones. Use $addFields when you only need a few computed columns.
$lookup performs a left outer join: every input document is kept, and matching foreign documents are attached in an array field (unless you use a correlated pipeline to reshape matches).
Use $facet when one query must return several independent views—such as a total count, a top-10 list, and a histogram—from the same filtered dataset without running separate queries.

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 $match in the learning path.
Did you know?

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.

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

9 people found this page helpful