The Aggregation Pipeline

The aggregation pipeline processes documents through a sequence of stages — filtering, grouping, and sorting — the MongoDB equivalent of a SQL query with WHERE, GROUP BY, and ORDER BY combined.

A single stage: $match

$match filters documents, using the exact same query syntax as find():

JS mongosh
db.posts.aggregate([
  { $match: { views: { $gt: 0 } } }
])
Output
[
  { _id: ObjectId("65f1a3104c1a2b3c4d5e6f71"), title: 'Hello, MongoDB!', author: 'Priya', views: 1, featured: true },
  { _id: ObjectId("65f1a3334c1a2b3c4d5e6f72"), title: 'Indexes Explained', author: 'Sam', views: 12 }
]

Grouping with $group

$group collapses documents sharing a key into one summary document per group — here, total views per author:

JS mongosh
db.posts.aggregate([
  { $group: { _id: "$author", totalViews: { $sum: "$views" } } }
])
Output
[
  { _id: 'Priya', totalViews: 1 },
  { _id: 'Sam', totalViews: 12 }
]

The $ in front of author and views means "read this field's value from the document" — without it, MongoDB would treat "author" as a literal string instead of a field reference.

Chaining stages: $match, $group, $sort

JS mongosh
db.posts.aggregate([
  { $match: { views: { $gt: 0 } } },
  { $group: { _id: "$author", totalViews: { $sum: "$views" } } },
  { $sort: { totalViews: -1 } }
])
Output
[
  { _id: 'Sam', totalViews: 12 },
  { _id: 'Priya', totalViews: 1 }
]

Each stage's output feeds into the next — filter first, then group, then sort the grouped results, exactly in the order the stages are written.

Order matters: put $match as early in the pipeline as possible. A $match stage placed before $group can use an index and discards non-matching documents immediately; the same $match placed after $group has to wait until every document has already been grouped, throwing away all that wasted work.