Applications and events

Build an aggregation pipeline

Transform documents in small stages with match, unwind, group, project, and sort while keeping early filtering visible.

9 minute lesson

~~~

An aggregation pipeline passes documents through ordered stages. Each stage filters, reshapes, groups, joins, or calculates data for the next stage. It is how you answer questions that find() cannot, like “what are the five most popular favorite foods among dogs?”

Build it one stage at a time, inspecting output after each addition. Start by filtering:

db.animals.aggregate([
  { $match: { species: 'dog' } }
])
// full dog documents, unchanged

Each dog has a favoriteFoods array. $unwind turns one document with three foods into three documents with one food each — that gives $group something to count:

db.animals.aggregate([
  { $match: { species: 'dog' } },
  { $unwind: '$favoriteFoods' },
  { $group: { _id: '$favoriteFoods', count: { $sum: 1 } } }
])
// [ { _id: 'biscuits', count: 12 }, { _id: 'carrots', count: 9 }, ... ]

Note the '$favoriteFoods' syntax: inside a pipeline, a string starting with $ refers to a field’s value. Finish with ordering and a bound:

db.animals.aggregate([
  { $match: { species: 'dog' } },
  { $unwind: '$favoriteFoods' },
  { $group: { _id: '$favoriteFoods', count: { $sum: 1 } } },
  { $sort: { count: -1 } },
  { $limit: 5 }
])

That is the report: top five foods, most popular first.

Stage order is performance

Place selective $match stages as early as possible. A $match at the start of the pipeline can use an index on the collection. The same condition placed after a $group cannot — by then the original documents are gone and MongoDB has already processed the entire collection to build the groups.

The failure mode looks like this: the pipeline returns correct results in development, then takes thirty seconds on the production collection with two million documents. Running the same pipeline with .explain() shows a COLLSCAN feeding the first stage. The fix is usually moving a filter earlier, or adding the index the early $match needs.

Keep each stage small enough to inspect on its own. And keep expectations honest: aggregation is powerful, but it does not make an unbounded data model or a missing index disappear. A pipeline that compensates for a bad document shape on every read is a signal to fix the shape.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →