Advanced Aggregation Pipelines
Combine multiple stages into a complete, real-world reporting pipeline, and learn $facet, $bucket, and $unwind for arrays.
$unwind for Array Fields
Beyond flattening a $lookup result, $unwind can deconstruct any array field, producing one output document per array element — useful for analyzing individual items within an order, for example.
db.orders.aggregate([ { $unwind: "$items" }, { $group: { _id: "$items.product", totalSold: { $sum: "$items.quantity" } } }, { $sort: { totalSold: -1 } },]);$facet: Multiple Pipelines at Once
$facet runs several independent sub-pipelines against the same input documents in one pass, returning all their results together — useful for building a single response that needs, say, both paginated results and a total count.
db.products.aggregate([ { $match: { category: "electronics" } }, { $facet: { paginatedResults: [{ $skip: 0 }, { $limit: 10 }], totalCount: [{ $count: "count" }], }, },]);$bucket for Histograms
$bucket groups documents into ranges you define — the standard way to build a histogram, like grouping products into price bands.
db.products.aggregate([ { $bucket: { groupBy: "$price", boundaries: [0, 25, 50, 100, 500], default: "500+", output: { count: { $sum: 1 } }, }, },]);A Complete Real-World Pipeline
Putting several stages together: a monthly sales report by product category, joining product details, filtering, grouping, and sorting.
db.orders.aggregate([ { $match: { status: "completed", createdAt: { $gte: ISODate("2026-01-01") } } }, { $unwind: "$items" }, { $lookup: { from: "products", localField: "items.productId", foreignField: "_id", as: "productInfo", }, }, { $unwind: "$productInfo" }, { $group: { _id: "$productInfo.category", totalRevenue: { $sum: { $multiply: ["$items.quantity", "$productInfo.price"] } }, unitsSold: { $sum: "$items.quantity" }, }, }, { $sort: { totalRevenue: -1 } },]);Common Beginner Mistakes
Comment out later stages and run just the first few to verify each transformation as you build up a complex pipeline — debugging a full pipeline's wrong output all at once is much harder.
Without unwinding first, $group would treat the whole array as a single value rather than processing each item individually.
FAQs
No hard limit on stage count, though very long pipelines are worth reviewing for opportunities to filter earlier or simplify.
Yes — the $merge and $out stages write pipeline output directly into a (new or existing) collection, useful for materializing a computed report.
Summary
$unwind, $facet, and $bucket round out the aggregation framework's toolkit for genuinely complex reporting and analysis pipelines. With the aggregation framework covered, the next section moves into integrating MongoDB with a real application via Mongoose.