$map, and how it differs from $unwind
$map applies an expression to every element of an array and gives you a new array back. It is the operator that lets you compute per-element values without $unwind scattering your document across many.
Suppose:
{
items: [
{
product: "Laptop",
price: 1000,
quantity: 2
},
{
product: "Mouse",
price: 50,
quantity: 3
}
]
}
You want:
[
{
product: "Laptop",
total: 2000
},
{
product: "Mouse",
total: 150
}
]
Use $map.
{
$project: {
items: {
$map: {
input: "$items",
as: "item",
in: {
product: "$$item.product",
total: {
$multiply: [
"$$item.price",
"$$item.quantity"
]
}
}
}
}
}
}
Mental model:
Array
[A, B, C]
$map
A → transformed A
B → transformed B
C → transformed C
Basically:
array.map(...)
from JavaScript.
$map vs $unwind
This distinction is important.
Suppose:
items[]
Use $map
When you want to:
Keep the array
but transform its elements.
Example:
items[]
↓ calculate totals
itemsWithTotal[]
Use $unwind
When you want:
One pipeline document per array element.
Example:
Order
├── Laptop
└── Mouse
↓
Order + Laptop
Order + Mouse
↓
$group by product
Remember:
Keep array structure
→ $map / $filter
Break array into documents
→ $unwind
Try it
db.orders.aggregate([
{
$project: {
_id: 0,
items: {
$map: {
input: "$items",
as: "item",
in: {
product: "$$item.product",
total: {
$multiply: ["$$item.price", "$$item.quantity"]
}
}
}
}
}
},
{ $limit: 3 }
])
Three documents in, three out, each with a rebuilt array. $unwind would have given you one document per item instead.