Aggregation Fundamentals
$sort, $limit and $skip
Order and slice after grouping — and why $sort before $limit can use an index.
Same idea as cursor sort / limit / skip, as stages. After $group, you must $sort if the ranking matters — groups come out unordered. $sort then $limit can be a top-k: the server does not have to fully sort every group when it only needs five.
db.products.aggregate([
{ $sort: { price: -1 } },
{ $limit: 5 },
{ $project: { _id: 0, name: 1, price: 1, category: 1 } }
])db.orders.aggregate([
{ $group: { _id: "$userId", totalSpent: { $sum: "$amount" } } },
{ $sort: { totalSpent: -1 } },
{ $limit: 10 }
])$skip has the same cost as skip() on find — walking n results. An early $sort+$limit before a heavy $lookup (next module) means you join ten documents, not the collection. A $sort on a field with an index, before a $group that destroys that field, can still use the index; after $group you are sorting computed totals in memory.
Interview question
Where do $sort and $limit go relative to $group?
If I am ranking groups — top spenders — $group, then $sort, then $limit. If I $limit first I only grouped a slice of orders. $sort before $group is for $first / $last to see a defined order.
Practice