MongoDB Stages

Beginner
10 min read
Updated: Oct 2026
Entry guide
Live examples

What Are MongoDB Stages?

MongoDB aggregation stages are the steps in a pipeline. Each stage starts with $ and does one job: filter, reshape, group, sort, join, or write results.

You pass an ordered array of stages to db.collection.aggregate([ ... ]). Documents flow through each stage in order—like an assembly line for analytics and reports.

Remember
Stage = one pipeline step that starts with $

Examples:
  $match   → filter documents
  $project → reshape fields
  $group   → summarize with accumulators
  $lookup  → join another collection

Browse every tutorial in the left sidebar.

How MongoDB Stages Work

A pipeline is an array. MongoDB runs stage 1 on the collection, feeds its output into stage 2, and so on until the final result cursor.

  1. Start from a collection with aggregate([ ... ]).
  2. Add stages in the order you want work done.
  3. Each stage transforms the document stream and passes it forward.
  4. Read the final cursor (or write with $out / $merge).
Where stages appearTypical use
Filter early$match to shrink the stream
Reshape fields$project / $addFields
Summarize$group with accumulators
Join collections$lookup + optional $unwind
Order & page$sort, $skip, $limit
mongosh
// Filter → group → sort
db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: { _id: "$storeId", revenue: { $sum: "$amount" } } },
  { $sort: { revenue: -1 } }
])

// Add a computed field without dropping others
db.orders.aggregate([
  { $addFields: { total: { $multiply: ["$qty", "$price"] } } }
])

How It Works

  1. $match. Keeps only completed orders.
  2. $group. Totals amount per storeId.
  3. $sort. Highest revenue first.
  4. $addFields. Adds total while keeping existing fields.

MongoDB Stage Syntax

Almost every stage uses the { $stageName: <spec> } form inside an aggregation array. The $ prefix marks a reserved stage name.

Pattern
db.collection.aggregate([
  { $stageName: <specification> },
  { $anotherStage: <specification> }
])

// Field path inside expressions:
"$fieldName"  → value of that field on the current document

$match

Filter documents (like find)

{ $match: { city: "Chennai" } }

$project

Include, exclude, or compute fields

{ $project: { name: 1, total: { $add: ["$a", "$b"] } } }

$group

Bucket and roll up with accumulators

{ $group: { _id: "$cat", n: { $sum: 1 } } }

$lookup

Left-outer join another collection

{ $lookup: { from: "users", localField: "userId", foreignField: "_id", as: "user" } }

Pseudocode

Use this mental model before you build a pipeline.

Pseudocode
goal = report / join / reshape / write results

stream = all documents in collection

for each stage in pipeline (in order):
    if stage is $match:
        stream = keep only matching docs
    else if stage is $project / $addFields:
        stream = reshape each document
    else if stage is $group:
        stream = one doc per bucket + accumulators
    else if stage is $sort / $limit:
        stream = ordered / trimmed stream
    else:
        stream = apply that stage's rule

return stream

How It Works

  1. Start from the goal, not from a random stage name.
  2. Filter early, then reshape or group, then sort/limit for the final view.
  3. Each stage only sees what the previous stage emitted.

Stage Categories

Major families below. The left sidebar lists every tutorial—this section only explains when each family is useful.

CategoryUsed forExamples
FilterKeep documents that match a condition$match
TransformReshape, add, remove, or replace fields$project, $addFields, $unset
Group & analyzeSummaries, histograms, multi-view results$group, $bucket, $facet
Sort & pageOrder results and take a window of rows$sort, $skip, $limit
Join & arraysRelate collections or flatten arrays$lookup, $unwind, $graphLookup
Geo & searchNearness queries and Atlas Search$geoNear, $search
WritePersist pipeline output to a collection$out, $merge
DiagnosticStats, sessions, ops, and change streams$collStats, $indexStats, $changeStream

For rollups inside $group, see the accumulators hub. For per-document expressions, see the operators hub.

Common MongoDB Stages

A short starter set. Open any name for a full tutorial; use the sidebar for the complete catalog.

StageQuick meaning
$matchFilter documents (find-style query)
$projectChoose or compute output fields
$addFields / $setAdd fields while keeping the rest
$groupBucket documents and run accumulators
$sortOrder the stream by one or more fields
$limit / $skipTake / offset documents (pagination)
$lookupJoin another collection
$unwindFlatten an array into one doc per element
$countReturn { count: N } for the stream
$facetRun several sub-pipelines in one query

Worked Example

Small orders collection. We filter completed orders, group by store, then sort by revenue.

Example 1 — Sample Data

Four orders across two stores.

mongosh
db.orders.insertMany([
  { _id: 1, storeId: "A", amount: 40, status: "completed" },
  { _id: 2, storeId: "A", amount: 60, status: "completed" },
  { _id: 3, storeId: "B", amount: 25, status: "completed" },
  { _id: 4, storeId: "A", amount: 15, status: "cancelled" }
]);

How It Works

  1. Insert four documents into orders.
  2. Store A has two completed orders and one cancelled.
  3. Store B has one completed order.

Example 2 — Filter, Group, Sort

Three stages: keep completed rows, total revenue per store, then rank stores.

mongosh
db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $group: {
      _id: "$storeId",
      revenue: { $sum: "$amount" },
      orders:  { $sum: 1 }
    }
  },
  { $sort: { revenue: -1 } }
]);

How It Works

  1. $match. Drops the cancelled order (_id: 4).
  2. $group. Buckets by storeId; $sum totals revenue and counts orders.
  3. $sort. Highest revenue first—store A (100) before B (25).

Choosing the Right Stage

Match the job to the family first; then pick a specific stage.

If you need to…Start with
Filter rows$match
Keep most fields and add a few$addFields / $set
Control exactly which fields survive$project
Totals or averages by category$group + accumulators
Join another collection$lookup
Flatten an array field$unwind
Several views in one query$facet
Save results to a collection$out or $merge

Edge Cases & Pitfalls

Common beginner traps when learning MongoDB stages.

order

Stage order changes results and cost

Put $match early to use indexes and shrink work. Sort before $group when $first / $last must be stable.

project

$project can drop fields you still need

Inclusive projections keep only listed fields (plus _id unless excluded). Prefer $addFields when you only want to add columns.

geo

$geoNear must be first

When you use $geoNear, it has to be the first stage in the pipeline.

write

$out / $merge change data

Most stages only return a result cursor. Write stages persist output—place them last and test carefully.

unwind

$unwind multiplies documents

An array of length N becomes N documents. Empty or missing arrays can drop rows unless you set preserveNullAndEmptyArrays.

context

Stages vs operators vs accumulators

Stages are pipeline steps. Expression operators run inside stages. Accumulators roll up values inside $group.

Performance Notes

IdeaPractical tip
Stages are not “slow by default”Cost comes from how much data each stage must process
Filter earlyPlace selective $match near the start
Indexes matterEarly $match / $sort can use indexes when the shape allows
Project lessDrop unused fields before heavy $group or $lookup
Limit while testingAdd temporary $limit while building pipelines

Use explain() when a pipeline feels slow. Prefer selective filters and smaller working sets over rearranging stages without a clear reason.

Key Takeaways

  • Stages are ordered pipeline steps that filter, reshape, group, join, or write.
  • Order matters: filter early, write late, sort before order-sensitive grouping.
  • Learn families, then open individual tutorials from the left sidebar.
  • Stages + operators + accumulators work together—each has a different job.

One line: Aggregation stages are the steps of the pipeline—order them to filter, transform, summarize, and deliver results.

Frequently Asked Questions

A stage is one step in an aggregation pipeline. Each stage receives documents from the previous stage, filters or transforms them, and passes the result forward. Stages run in array order inside db.collection.aggregate([ ... ]).
The leading $ marks a reserved stage name so MongoDB can tell pipeline stages apart from ordinary field names in documents.
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.
Yes. A pipeline is an ordered list of stages. Common patterns include $match → $group → $sort → $limit, or $lookup → $unwind for joins.
Use the left sidebar on this section to open each tutorial under /mongodb/stages/<name>. This page is the overview; individual pages cover syntax, examples, and pitfalls in depth.
Stages ($match, $group) are pipeline steps. Operators ($add, $cond) are expressions inside stages. Accumulators ($sum, $avg) run inside $group to compute one value per bucket.

Next: $addFields

Add computed fields while keeping the rest of each document.

$addFields tutorial →

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.

11 people found this page helpful