After this lesson, you will be able to: Use the aggregation pipeline: $match, $group, $project, $sort, $limit, $lookup, $unwind.
Aggregation pipeline is Mongo's reporting + analytics engine. Think 'SQL GROUP BY + JOIN' but as a chain of transformations. Required reading for any production Mongo work.
An array of stages; each stage transforms the docs flowing through.
db.orders.aggregate([{ $match: { status: "complete" } }, // filter (like WHERE){ $group: { // group + aggregate_id: "$customerId",total: { $sum: "$amount" },count: { $sum: 1 }}},{ $sort: { total: -1 } }, // sort{ $limit: 10 } // top 10 customers by spend]);
Filter early; shape later.
db.users.aggregate([{ $match: { active: true, age: { $gte: 18 } } },{ $project: {_id: 0,name: 1,email: 1,city: "$address.city", // rename nested fieldisAdult: { $gte: ["$age", 18] } // computed field}}]);// Put $match as early as possible, Mongo can push it to indexes
Reduce many docs to one per group.
// Revenue by monthdb.orders.aggregate([{ $match: { paidAt: { $exists: true } } },{ $group: {_id: {year: { $year: "$paidAt" },month: { $month: "$paidAt" }},revenue: { $sum: "$amount" },count: { $sum: 1 },avgOrder: { $avg: "$amount" }}},{ $sort: { "_id.year": 1, "_id.month": 1 } }]);// _id: null groups everything into ONE result rowdb.orders.aggregate([{ $group: { _id: null, total: { $sum: "$amount" } } }]);
Yes, Mongo has joins (since 3.2).
// Orders + customer detailsdb.orders.aggregate([{ $lookup: {from: "users", // collection to joinlocalField: "customerId",foreignField: "_id",as: "customer" // result lives here}},{ $unwind: "$customer" }, // explode the array (1 customer per order){ $project: {orderId: "$_id",amount: 1,customerName: "$customer.name"}}]);// $lookup is correct but slower than relational joins.// If you do many $lookups, MAYBE you needed a relational DB.
One doc per array element.
// Schema: { _id, name, tags: ['a', 'b', 'c'] }db.users.aggregate([{ $unwind: "$tags" }]);// → { _id, name, tags: 'a' }, { _id, name, tags: 'b' }, { _id, name, tags: 'c' }// Often paired with $group to count tag usagedb.users.aggregate([{ $unwind: "$tags" },{ $group: { _id: "$tags", count: { $sum: 1 } } },{ $sort: { count: -1 } }]);
$match late in pipeline (forces full collection scan). $lookup over and over (you're working against the data model, consider relational DB). Aggregating without indexes, slow on big collections. Misreading $sum: 1 vs $sum: '$count' (the first counts docs; the second sums the existing count field).
Sign in and purchase access to unlock this lesson.