MongoDB Aggregation: $sort, $skip, $limit, $unwind and $out Stages
Learn the remaining MongoDB aggregation pipeline stages — $sort, $skip, $limit for ordering and paging results, $unwind for arrays, and $out to save results to a new collection.
$sort, $skip, $limit, $unwind and $out
$sort
Reorders the documents flowing through the pipeline — works the same as find().sort().
db.employees.aggregate([
{ $project: { name: 1, email: 1 } },
{ $sort: { name: 1 } }
])
db.employees.aggregate([
{ $group: { _id: "$age", sumCity: { $sum: 1 } } },
{ $sort: { sumCity: -1 } }
])
// sort by a value computed earlier in the SAME pipeline
$skip
db.employees.aggregate([
{ $match: { gender: "F" } },
{ $skip: 1 }
])
$limit
db.employees.aggregate([
{ $match: { gender: "M" } },
{ $project: { name: 1 } },
{ $limit: 2 }
])
$sort, $skip and $limit combine inside a pipeline the same way they do with find() — for paging aggregated results.
$unwind
Arrays can't be worked with directly by stages like $group. $unwind "flattens" an array field by outputting one copy of the document per array element.
If empid: 202 has lang: ["Hindi", "English"], unwinding lang turns that single document into two: one with lang: "Hindi", one with lang: "English" (every other field stays the same on both copies).
db.employees.aggregate([
{ $match: { empid: 202 } },
{ $unwind: "$lang" }
])
db.employees.aggregate([
{ $match: { empid: 202 } },
{ $unwind: "$deptwork" }
])
This is usually the step right before a $group that needs to tally up individual array elements (e.g. "how many employees speak each language?").
$out — Save Results to a New Collection
Writes the final pipeline output into a brand-new (or existing, after dropping it) collection instead of just returning it. $out must be the last stage in the pipeline.
db.employees.aggregate([
{ $match: { gender: "F" } },
{ $out: "femaleEmp" }
])
show collections
db.femaleEmp.find()
db.employees.aggregate([
{ $group: { _id: "$age", sumAge: { $sum: 1 } } },
{ $out: "sameAgeCount" }
])
Common Errors & Troubleshooting
$unwindon a document with an empty array removes it entirely — by default, a document whose array field is[]or missing disappears from the pipeline after$unwind; pass{ path: "$field", preserveNullAndEmptyArrays: true }if you need to keep those documents.$outoverwriting an existing collection without warning —$outreplaces the target collection's entire contents if it already exists — always double-check the target name before running it in production.$sortinside the pipeline needing a lot of memory on huge datasets — sorting a very large intermediate result can hit MongoDB's in-memory sort limit; add an index that supports the sort, or sort earlier in the pipeline on a smaller intermediate result.
Key Takeaways
$unwindis the bridge between array fields and stages like$groupthat can't reach inside arrays directly.$sort/$skip/$limitwork the same inside an aggregation pipeline as they do chained ontofind().$outpersists your aggregation result as a real collection — but it must be the final stage.