1. What is MongoDB Aggregation?
MongoDB aggregation is a way to process and transform data inside the database.
Think of it like a pipeline:
Documents → Step 1 → Step 2 → Step 3 → Result
Each step modifies, filters, groups, or reshapes the data.
MongoDB uses the Aggregation Pipeline:
db.collection.aggregate([
{ stage1 },
{ stage2 },
{ stage3 }
])2. Why Use Aggregation?
Aggregation helps you:
- Filter data
- Group documents
- Calculate totals/averages
- Join collections
- Transform fields
- Sort & paginate
- Build analytics
Similar to:
- SQL GROUP BY
- SQL JOIN
- SQL calculations
3. Sample Data
We'll use this sample data to demonstrate aggregation stages:
[
{
_id: 101,
name: "iPhone 15",
category: "Mobile",
brand: "Apple",
price: 85000,
stock: 12,
tags: ["electronics", "phone", "ios"],
ratings: [5, 4, 5, 3, 4],
createdAt: new Date("2025-01-10")
},
{
_id: 102,
name: "Samsung S24",
category: "Mobile",
brand: "Samsung",
price: 72000,
stock: 20,
tags: ["android", "electronics"],
ratings: [4, 4, 5],
createdAt: new Date("2025-02-11")
},
{
_id: 103,
name: "MacBook Air",
category: "Laptop",
brand: "Apple",
price: 120000,
stock: 7,
tags: ["laptop", "macos"],
ratings: [5, 5, 5],
createdAt: new Date("2024-09-01")
},
{
_id: 104,
name: "Boat Headphones",
category: "Accessories",
brand: "Boat",
price: 2500,
stock: 50,
tags: ["audio", "music"],
ratings: [3, 4, 4],
createdAt: new Date("2025-03-14")
},
{
_id: 105,
name: "Gaming Mouse",
category: "Accessories",
brand: "Logitech",
price: 1800,
stock: 35,
tags: ["gaming", "pc"],
ratings: [5, 4, 4, 5],
createdAt: new Date("2025-01-20")
}
];[
{
_id: 1001,
userId: 1,
products: [
{
productId: 101,
quantity: 1
},
{
productId: 104,
quantity: 2
}
],
totalAmount: 90000,
status: "DELIVERED",
paymentMethod: "UPI",
shippingAddress: {
city: "Bhagalpur",
state: "Bihar"
},
orderDate: new Date("2025-04-01")
},
{
_id: 1002,
userId: 2,
products: [
{
productId: 102,
quantity: 1
}
],
totalAmount: 72000,
status: "PENDING",
paymentMethod: "Card",
shippingAddress: {
city: "Patna",
state: "Bihar"
},
orderDate: new Date("2025-04-05")
},
{
_id: 1003,
userId: 3,
products: [
{
productId: 103,
quantity: 1
},
{
productId: 105,
quantity: 2
}
],
totalAmount: 123600,
status: "DELIVERED",
paymentMethod: "NetBanking",
shippingAddress: {
city: "Delhi",
state: "Delhi"
},
orderDate: new Date("2025-04-10")
},
{
_id: 1004,
userId: 1,
products: [
{
productId: 105,
quantity: 3
}
],
totalAmount: 5400,
status: "CANCELLED",
paymentMethod: "COD",
shippingAddress: {
city: "Bhagalpur",
state: "Bihar"
},
orderDate: new Date("2025-04-15")
},
{
_id: 1011,
userId: 2,
products: [
{
productId: 101,
quantity: 1
},
{
productId: 104,
quantity: 2
}
],
totalAmount: 90000,
status: "DELIVERED",
paymentMethod: "UPI",
shippingAddress: {
city: "Patna",
state: "Bihar"
},
orderDate: new Date()
},
{
_id: 1012,
userId: 1,
products: [
{
productId: 103,
quantity: 1
}
],
totalAmount: 120000,
status: "DELIVERED",
paymentMethod: "Card",
shippingAddress: {
city: "Bhagalpur",
state: "Bihar"
},
orderDate: new Date(Date.now() - 5 * 60 * 60 * 1000)
},
{
_id: 1013,
userId: 3,
products: [
{
productId: 105,
quantity: 3
}
],
totalAmount: 5400,
status: "PENDING",
paymentMethod: "COD",
shippingAddress: {
city: "Delhi",
state: "Delhi"
},
orderDate: new Date(Date.now() - 10 * 60 * 60 * 1000)
}
];4. Most Important Aggregation Stages
4.1. $match : Filter Documents
Like SQL WHERE.
$match is used to:
Filter documents based on a condition.
1. Filter pending orders.
db.orders.aggregate([
{
$match: {
status: "PENDING"
}
}
]);Output:
[
{
_id: 1002,
userId: 2,
products: [ { productId: 102, quantity: 1 } ],
totalAmount: 72000,
status: 'PENDING',
paymentMethod: 'Card',
shippingAddress: { city: 'Patna', state: 'Bihar' },
orderDate: ISODate('2025-04-05T00:00:00.000Z')
},
{
_id: 1013,
userId: 3,
products: [ { productId: 105, quantity: 3 } ],
totalAmount: 5400,
status: 'PENDING',
paymentMethod: 'COD',
shippingAddress: { city: 'Delhi', state: 'Delhi' },
orderDate: ISODate('2026-05-27T01:30:29.284Z')
}
]2. Filter all products whose price is greater than 10000.
db.products.aggregate([
{
$match: {
price: {
$gt: 10000
}
}
}
]);Output:
[
{
_id: 101,
name: "iPhone 15",
category: "Mobile",
brand: "Apple",
price: 85000,
stock: 12,
tags: ["electronics", "phone", "ios"],
ratings: [5, 4, 5, 3, 4],
createdAt: ISODate("2025-01-10T00:00:00.000Z")
},
{
_id: 102,
name: "Samsung S24",
category: "Mobile",
brand: "Samsung",
price: 72000,
stock: 20,
tags: ["android", "electronics"],
ratings: [4, 4, 5],
createdAt: ISODate("2025-02-11T00:00:00.000Z")
},
{
_id: 103,
name: "MacBook Air",
category: "Laptop",
brand: "Apple",
price: 120000,
stock: 7,
tags: ["laptop", "macos"],
ratings: [5, 5, 5],
createdAt: ISODate("2024-09-01T00:00:00.000Z")
}
];4.2 $group : Group Documents
Like SQL GROUP BY.
$group is used to:
Group documents by a common field and apply an aggregation operation to each group.
_id means: Group by this field Not the actual MongoDB document ID.
1. Count how many products are in each category.
db.products.aggregate([
{
$group: {
_id: "$category",
totalProducts: {
$sum: 1
},
products: {
$push: {
_id: "$_id",
name: "$name",
price: "$price"
}
}
}
}
]);Output:
[
{
_id: "Accessories",
totalProducts: 2,
products: [
{
_id: 104,
name: "Boat Headphones",
price: 2500
},
{
_id: 105,
name: "Gaming Mouse",
price: 1800
}
]
},
{
_id: "Laptop",
totalProducts: 1,
products: [
{
_id: 103,
name: "MacBook Air",
price: 120000
}
]
},
{
_id: "Mobile",
totalProducts: 2,
products: [
{
_id: 101,
name: "iPhone 15",
price: 85000
},
{
_id: 102,
name: "Samsung S24",
price: 72000
}
]
}
];2. Count total stock & products per category.
db.products.aggregate([
{
$group: {
_id: "$category",
totalProducts: {
$sum: 1
},
totalStock: {
$sum: "$stock"
}
}
}
]);Output:
[
{
_id: "Mobile",
totalProducts: 2,
totalStock: 32
},
{
_id: "Laptop",
totalProducts: 1,
totalStock: 7
},
{
_id: "Accessories",
totalProducts: 2,
totalStock: 85
}
];3. Count total price per category.
db.products.aggregate([
{
$group: {
_id: "$category",
totalPrice: {
$sum: "$price"
}
}
}
]);Output:
[
{ _id: "Mobile", totalPrice: 157000 },
{ _id: "Laptop", totalPrice: 120000 },
{ _id: "Accessories", totalPrice: 4300 }
];4.3 $project : Select/Transform Fields
$project is used to:
Select or transform fields in the output documents.
db.products.aggregate([
{
$match: {
brand: "Apple"
}
},
{
$project: {
name: 1,
price: 1,
category: 1,
brand: 1
}
}
]);Output:
[
{
_id: 101,
name: 'iPhone 15',
category: 'Mobile',
brand: 'Apple',
price: 85000
},
{
_id: 103,
name: 'MacBook Air',
category: 'Laptop',
brand: 'Apple',
price: 120000
}
]4.4 $sort : Sort Documents
$sort is used to:
Sort documents in ascending or descending order.
db.products.aggregate([
{
$match: {
brand: "Apple"
}
},
{
$project: {
name: 1,
price: 1,
category: 1,
brand: 1
}
},
{
$sort: {
price: 1
}
}
]);- 1 : sort by ascending order.
- -1 : sort by descending order.
Output:
[
{
_id: 101,
name: 'iPhone 15',
category: 'Mobile',
brand: 'Apple',
price: 85000
},
{
_id: 103,
name: 'MacBook Air',
category: 'Laptop',
brand: 'Apple',
price: 120000
}
]4.5 $limit : Limit Documents
$limit is used to:
Limit the number of documents returned.
db.products.aggregate([
{
$limit: 3
}
]);Output:
[
{
_id: 101,
name: "iPhone 15",
category: "Mobile",
brand: "Apple",
price: 85000,
stock: 12,
tags: ["electronics", "phone", "ios"],
ratings: [5, 4, 5, 3, 4],
createdAt: ISODate("2025-01-10T00:00:00.000Z")
},
{
_id: 102,
name: "Samsung S24",
category: "Mobile",
brand: "Samsung",
price: 72000,
stock: 20,
tags: ["android", "electronics"],
ratings: [4, 4, 5],
createdAt: ISODate("2025-02-11T00:00:00.000Z")
},
{
_id: 103,
name: "MacBook Air",
category: "Laptop",
brand: "Apple",
price: 120000,
stock: 7,
tags: ["laptop", "macos"],
ratings: [5, 5, 5],
createdAt: ISODate("2024-09-01T00:00:00.000Z")
}
];4.6 $skip : Skip Documents
$skip is used to:
Skip documents before returning the first document. Useful for pagination.
db.products.aggregate([
{
$skip: 2
}
]);Output:
[
{
_id: 103,
name: "MacBook Air",
category: "Laptop",
brand: "Apple",
price: 120000,
stock: 7,
tags: ["laptop", "macos"],
ratings: [5, 5, 5],
createdAt: ISODate("2024-09-01T00:00:00.000Z")
},
{
_id: 104,
name: "Boat Headphones",
category: "Accessories",
brand: "Boat",
price: 2500,
stock: 50,
tags: ["audio", "music"],
ratings: [3, 4, 4],
createdAt: ISODate("2025-03-14T00:00:00.000Z")
},
{
_id: 105,
name: "Gaming Mouse",
category: "Accessories",
brand: "Logitech",
price: 1800,
stock: 35,
tags: ["gaming", "pc"],
ratings: [5, 4, 4, 5],
createdAt: ISODate("2025-01-20T00:00:00.000Z")
}
];4.7 $lookup : Join Collections
Like SQL JOIN.
$lookup is used to:
Join data from other collections.
1. Find two orders with products details.
db.orders.aggregate([
{
$lookup: {
from: "products",
localField: "products.productId",
foreignField: "_id",
as: "productDetails"
}
},
{
$limit: 2
}
]);Output:
[
{
_id: 1001,
userId: 1,
products: [
{ productId: 101, quantity: 1 },
{ productId: 104, quantity: 2 }
],
totalAmount: 90000,
status: "DELIVERED",
paymentMethod: "UPI",
shippingAddress: { city: "Bhagalpur", state: "Bihar" },
orderDate: ISODate("2025-04-01T00:00:00.000Z"),
productDetails: [
{
_id: 104,
name: "Boat Headphones",
category: "Accessories",
brand: "Boat",
price: 2500,
stock: 50,
tags: ["audio", "music"],
ratings: [3, 4, 4],
createdAt: ISODate("2025-03-14T00:00:00.000Z")
},
{
_id: 101,
name: "iPhone 15",
category: "Mobile",
brand: "Apple",
price: 85000,
stock: 12,
tags: ["electronics", "phone", "ios"],
ratings: [5, 4, 5, 3, 4],
createdAt: ISODate("2025-01-10T00:00:00.000Z")
}
]
},
{
_id: 1002,
userId: 2,
products: [{ productId: 102, quantity: 1 }],
totalAmount: 72000,
status: "PENDING",
paymentMethod: "Card",
shippingAddress: { city: "Patna", state: "Bihar" },
orderDate: ISODate("2025-04-05T00:00:00.000Z"),
productDetails: [
{
_id: 102,
name: "Samsung S24",
category: "Mobile",
brand: "Samsung",
price: 72000,
stock: 20,
tags: ["android", "electronics"],
ratings: [4, 4, 5],
createdAt: ISODate("2025-02-11T00:00:00.000Z")
}
]
}
];2. Find orders with products details(_id, name, price, brand).
db.orders.aggregate([
{
$lookup: {
from: "products",
localField: "products.productId",
foreignField: "_id",
pipeline: [
{
$project: {
name: 1,
price: 1,
brand: 1
}
}
],
as: "productDetails"
}
},
{
$limit: 2
}
]);Output:
[
{
_id: 1001,
userId: 1,
products: [
{
productId: 101,
quantity: 1
},
{
productId: 104,
quantity: 2
}
],
totalAmount: 90000,
status: "DELIVERED",
paymentMethod: "UPI",
shippingAddress: {
city: "Bhagalpur",
state: "Bihar"
},
orderDate: ISODate("2025-04-01T00:00:00.000Z"),
productDetails: [
{
_id: 101,
name: "iPhone 15",
brand: "Apple",
price: 85000
},
{
_id: 104,
name: "Boat Headphones",
brand: "Boat",
price: 2500
}
]
},
{
_id: 1002,
userId: 2,
products: [
{
productId: 102,
quantity: 1
}
],
totalAmount: 72000,
status: "PENDING",
paymentMethod: "Card",
shippingAddress: {
city: "Patna",
state: "Bihar"
},
orderDate: ISODate("2025-04-05T00:00:00.000Z"),
productDetails: [
{
_id: 102,
name: "Samsung S24",
brand: "Samsung",
price: 72000
}
]
}
];4.8 $unwind : Unwind Arrays
$unwind is used to:
Break an array into separate documents.
1. Unwind ratings array.
db.products.aggregate([
{
$unwind: "$ratings"
},
{
$project: {
name: 1,
ratings: 1
}
},
{
$limit: 4
}
]);Output:
[
{
_id: 101,
name: "iPhone 15",
ratings: 5
},
{
_id: 101,
name: "iPhone 15",
ratings: 4
},
{
_id: 101,
name: "iPhone 15",
ratings: 5
},
{
_id: 101,
name: "iPhone 15",
ratings: 3
}
];2. Count How Many Times Each Rating Appears
db.products.aggregate([
{
$unwind: "$ratings"
},
{
$group: {
_id: "$ratings",
total: {
$sum: 1
}
}
},
{
$sort: {
_id: -1
}
}
]);Output:
[
{ _id: 5, total: 8 },
{ _id: 4, total: 8 },
{ _id: 3, total: 2 }
];5. Aggregation Pipeline Example
Find the total revenue generated by each category of products in the last 24 hours.
db.orders.aggregate([
{
$match: {
// last 24 hours
orderDate: {
$gt: new Date(Date.now() - 24 * 60 * 60 * 1000)
}
}
},
{
$project: {
products: 1
}
},
{
$unwind: "$products"
},
{
$lookup: {
from: "products",
localField: "products.productId",
foreignField: "_id",
as: "productDetails"
}
},
{
$unwind: "$productDetails"
},
{
$group: {
_id: "$productDetails.category",
totalRevenue: {
$sum: {
$multiply: ["$products.quantity", "$productDetails.price"]
}
}
}
}
]);Output:
[
{ _id: "Accessories", totalRevenue: 10400 },
{ _id: "Laptop", totalRevenue: 120000 },
{ _id: "Mobile", totalRevenue: 85000 }
];6. MongoDB Aggregation Stages & Their Uses
| Stage | Use |
|---|---|
| $match | Filter documents |
| $group | Group documents and calculate values |
| $project | Select, remove, rename, or transform fields |
| $sort | Sort documents |
| $limit | Limit number of documents |
| $skip | Skip documents |
| $unwind | Split array into multiple documents |
| $lookup | Join another collection |
| $addFields | Add new fields |
| $set | Same as $addFields |
| $unset | Remove fields |
| $count | Count total documents |
| $sample | Get random documents |
| $replaceRoot | Replace entire document |
| $replaceWith | Same as $replaceRoot |
| $sortByCount | Group, count, and sort documents |
| $unionWith | Combine multiple collections |
| $out | Save aggregation result into collection |
| $geoNear | Find nearby locations |