find() retrieves documents. The aggregation pipeline transforms them — filtering, grouping, reshaping, and computing new values, all in one operation made of chained stages, each one feeding its output into the next.
Call aggregate() with an array of stage objects — each object's key is the stage operator, starting with $:
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $project: { customerId: "$_id", total: 1, _id: 0 } }
])$match works like a find() query, and is usually the first stage — filtering early means every following stage processes fewer documents:
{ $match: { status: "completed" } }$group collapses many documents into one per distinct value of _id, computing a value for each group with an accumulator like $sum, $avg, $max, or $count:
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } }$project works like a projection in find(), but can also compute new fields, not just include or exclude existing ones:
{ $project: { customerId: "$_id", total: 1, _id: 0 } }These three stages go a long way
These three stages alone — $match, $group, $project — already cover a large share of real reporting queries: "total spend per customer," "orders per day," "average rating per product."