Aggregation PipelineLesson 4.4
MongoDB $unwind, $addFields, and $bucket stages explained
$unwind array deconstruction, preserveNullAndEmpty, $addFields vs $project, $bucket for histograms, $bucketAuto, $facet for multi-dimensional aggregation
$unwind — one document per array element
$unwind deconstructs an array field into one output document per element. A document with a 3-element tags array becomes 3 separate documents, each identical except the array field is replaced with a single scalar value. This is essential before running $group on array element values like tags, categories, or SKUs.
// Count how many times each tag appears across all posts
const popular = await db.collection('posts').aggregate([
{ $unwind: '$tags' }, // one doc per tag
{ $group: { _id: '$tags', count: { $sum: 1 } } },
{ $sort: { count: -1 } },
{ $limit: 10 } // top 10
]).toArray()
// Preserve documents with null or missing array fields
{ $unwind: { path: '$tags', preserveNullAndEmptyArrays: true } }$addFields — add computed fields non-destructively
Unlike $project which requires you to explicitly list every field you want to keep, $addFields only appends or overwrites the named fields — all existing document fields pass through automatically.
{ $addFields: {
totalWithTax: { $multiply: ['$total', 1.18] },
isPremiumOrder: { $gt: ['$total', 1000] },
orderMonth: { $month: '$createdAt' }
}}$bucket — histogram grouping
db.collection('orders').aggregate([{ $bucket: {
groupBy: '$total',
boundaries: [0, 50, 100, 250, 500, 1000],
default: 'Over 1000',
output: { count: { $sum: 1 }, avgTotal: { $avg: '$total' } }
}}])