Aggregation Overview
The aggregation pipeline runs documents through a series of stages — filter, transform, group, join, sort, lookup. It’s Mongo’s SQL-equivalent for analytics queries.
Real pipelines you will write
EXAMPLE
// 1) Top users by post count in the last 7 days
await db.posts.aggregate([
{ $match: { createdAt: { $gte: weekAgo() } } },
{ $group: { _id: '$userId', n: { $sum: 1 } } },
{ $sort: { n: -1 } },
{ $limit: 20 },
{ $lookup: {
from: 'users',
localField: '_id',
foreignField: '_id',
as: 'user',
} },
{ $unwind: '$user' },
{ $project: { _id: 0, email: '$user.email', n: 1 } },
]).toArray();
// 2) Revenue per category — group + add fields
await db.orders.aggregate([
{ $match: { status: 'paid', createdAt: { $gte: monthStart() } } },
{ $unwind: '$items' },
{ $group: {
_id: '$items.category',
revenue: { $sum: { $multiply: ['$items.price', '$items.qty'] } },
units: { $sum: '$items.qty' },
orders: { $addToSet: '$_id' },
} },
{ $addFields: { orderCount: { $size: '$orders' } } },
{ $project: { orders: 0 } },
{ $sort: { revenue: -1 } },
]).toArray();
// 3) Time-series rollups — group by day
await db.events.aggregate([
{ $match: { ts: { $gte: weekAgo() } } },
{ $group: {
_id: { $dateTrunc: { date: '$ts', unit: 'day' } },
n: { $sum: 1 },
} },
{ $sort: { _id: 1 } },
]).toArray();
// 4) Faceted query — multiple aggregations in one round trip
await db.products.aggregate([
{ $facet: {
byCategory: [{ $group: { _id: '$category', n: { $sum: 1 } } }],
byPriceBucket: [
{ $bucket: {
groupBy: '$price',
boundaries: [0, 10, 50, 100, 500, 10000],
default: 'over',
output: { n: { $sum: 1 } },
} },
],
topRated: [
{ $sort: { rating: -1 } },
{ $limit: 5 },
{ $project: { name: 1, rating: 1 } },
],
} },
]).toArray();
// 5) Use indexes!
// db.posts.createIndex({ userId: 1, createdAt: -1 })
// runs $match + $group above as index scans, not collection scans.
Why it matters
Always put $match first and use indexes that cover its fields. The optimiser pushes filters as early as possible, but you can’t skip the index design step.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
db.orders.aggregate([
{ $match: { status: 'paid' } },
{ $group: { _id: '$customer_id', total: { $sum: '$total' } } },
{ $sort: { total: -1 } },
]);
Try it Yourself »
Exercise
Aggregation operator to filter rows early.
{
: { status: 'paid' } }
Starts with $; six chars total.
Discussion
Loading…