Skip to content

Advanced Aggregation

$sample, $sortByCount and $replaceRoot

Sampling documents, grouping-and-counting in one stage, and promoting a nested document to the root.

AdvancedAbout 6 minutes

Three stages that show up once, then you stop looking them up. None of them replace $group / $sort / $project as the default tools.

db.products.aggregate([
  { $match: { category: "electronics" } },
  { $sample: { size: 5 } }
])
$sample — random documents. Not page 2.

$sample is for a random subset (QA, a 'featured' widget). It is not stable pagination. Do not $skip after it and expect the next five. Large samples can be expensive; a $match in front still helps.

db.users.aggregate([
  { $sortByCount: "$city" }
])
$sortByCount — $group + $sort by count descending
{ _id: "Bangalore", count: 12 }
{ _id: "Pune", count: 9 }

The count field is always count. You cannot rename it in this stage. Need totalUsers or a second accumulator? Use $group + $sort like Module 6.

db.orders.aggregate([
  { $unwind: "$items" },
  { $replaceRoot: { newRoot: "$items" } }
])
$replaceRoot — the nested document becomes the result
{ name: "Mechanical Keyboard", quantity: 1, unitPrice: 4500 }
{ name: "USB-C Cable", quantity: 2, unitPrice: 200 }
Parent amount / status are gone. You are looking at line items.

$replaceWith is the same stage (newer name). After $lookup + $unwind, $replaceRoot: { newRoot: "$user" } is how you return user documents and drop the wrapper — you also drop totalSpent unless you $mergeObjects first (expressions). If you still need parent fields, $project / $set is clearer than replace.

Interview question

What are $sample, $sortByCount and $replaceRoot each for?

Think about it first.