MongoDB Aggregation Pipeline stages
MongoDB’s aggregation pipeline is a powerful framework for transforming, filtering, and analyzing data in collections similar to SQL’s GROUP BY, JOIN, WHERE, etc.
🧱 Basic Structure
An aggregation pipeline is an array of stages, each stage transforms the documents and passes them to the next stage.
db.collection.aggregate([
{ <stage1> },
{ <stage2> },
...
])
1️⃣ $match - Filtering Documents
Works like the find() query. Filters documents based on conditions.
Example:
db.orders.aggregate([
{ $match: { status: "delivered" } }
])
✅ Returns only documents where status = "delivered".
2️⃣ $project - Select or Reshape Fields
Used to include/exclude fields or create computed fields.
Example:
db.orders.aggregate([
{
$project: {
_id: 0,
item: 1,
total: { $multiply: ["$price", "$quantity"] }
}
}
])
✅ Outputs only item and a computed field total.
3️⃣ $group - Group Documents & Aggregate Data
Groups documents by a key and applies aggregation operators (like $sum, $avg, etc.).
Example:
db.orders.aggregate([
{
$group: {
_id: "$customerId",
totalSpent: { $sum: { $multiply: ["$price", "$quantity"] } },
numOrders: { $sum: 1 }
}
}
])
✅ Groups by customer and calculates:
- Total spent
- Number of orders
4️⃣ $sort - Sort Results
Sorts documents by one or more fields.
Example:
db.orders.aggregate([
{ $sort: { total: -1 } } // descending
])
✅ Sorts by total in descending order.
5️⃣ $limit and $skip - Pagination
-
$limit: Restricts the number of documents. -
$skip: Skips a number of documents.
Example:
db.orders.aggregate([
{ $sort: { date: -1 } },
{ $skip: 10 },
{ $limit: 5 }
])
✅ Skips first 10, returns next 5 (useful for pagination).
6️⃣ $unwind - Deconstruct Arrays
Splits array fields into multiple documents (one per element).
Example:
db.orders.aggregate([
{ $unwind: "$items" }
])
✅ If a document has an array items: [a, b, c], it becomes 3 documents - one for each item.
7️⃣ $lookup - Join with Another Collection
Performs a left outer join between two collections.
Example:
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
}
])
✅ Adds matching customer info to each order under the field customer.
8️⃣ $addFields - Add or Modify Fields
Adds new fields or modifies existing ones.
Example:
db.orders.aggregate([
{
$addFields: {
total: { $multiply: ["$price", "$quantity"] },
statusUpper: { $toUpper: "$status" }
}
}
])
✅ Adds computed total and uppercase status.
9️⃣ $count - Count Documents
Counts the number of documents in the pipeline.
Example:
db.orders.aggregate([
{ $match: { status: "pending" } },
{ $count: "pendingOrders" }
])
✅ Returns { pendingOrders: 12 }.
🔟 $facet - Multiple Pipelines in One
Allows parallel aggregations on the same dataset.
Example:
db.orders.aggregate([
{
$facet: {
totalByCustomer: [
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } }
],
avgOrderValue: [
{ $group: { _id: null, avg: { $avg: "$amount" } } }
]
}
}
])
✅ Runs two aggregations in one pipeline.
1️⃣1️⃣ $bucket - Categorize Into Ranges
Groups values into defined ranges (buckets).
Example:
db.sales.aggregate([
{
$bucket: {
groupBy: "$amount",
boundaries: [0, 100, 500, 1000],
default: "Other",
output: { count: { $sum: 1 } }
}
}
])
✅ Categorizes sales by amount ranges.
1️⃣2️⃣ $out - Write Results to a Collection
Saves aggregation results into a new collection.
Example:
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $out: "completedOrders" }
])
✅ Writes output into a new collection completedOrders.
1️⃣3️⃣ $merge - Merge Results into an Existing Collection
Similar to $out, but can update or insert documents.
Example:
db.orders.aggregate([
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $merge: { into: "customerTotals", whenMatched: "merge", whenNotMatched: "insert" } }
])
✅ Updates or inserts aggregated data into customerTotals.
Let me know if this helped you in some way.
Top comments (0)