Script Valley
MongoDB: Complete Course
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 deconstruction

$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' } }
}}])

Up next

How to write MongoDB aggregation pipelines for real analytics

Sign in to track progress