Sample Input Documents
Suppose you have a students collection:
[
{
"_id": 1,
"name": "Alice",
"scores": [70, 85, 90]
},
{
"_id": 2,
"name": "Bob",
"scores": [60, 75, 80]
}
] 
The $reduce operator folds an array into a single value by processing each element with an accumulator. Use it to sum scores, find a maximum, concatenate strings, or build any custom aggregation over an array field.
Array → one value.
input + initialValue + in.
Running accumulator.
Current element.
Sum, max, concat.
Fold vs transform.
In MongoDB’s aggregation framework, the $reduce operator walks through an array element by element, updating an accumulator at each step. You provide the source array (input), a starting value (initialValue), and an expression (in) that combines the accumulator with the current element.
For example, summing [10, 20, 30] with initialValue: 0 produces 60. Unlike $map, which returns a new array, $reduce returns one final result per document.
Think of $reduce as MongoDB’s version of Array.reduce(). Inside in, $$value is the running total so far and $$this is the current array item. Both use the double-dollar prefix.
The $reduce operator takes an object with input, initialValue, and in:
{
$reduce: {
input: <array expression>,
initialValue: <expression>,
in: <expression>
}
} in// Sum numbers
{ $add: [ "$$value", "$$this" ] }
// Find maximum
{ $max: [ "$$value", "$$this" ] }
// Concatenate strings
{ $concat: [ "$$value", ", ", "$$this" ] }
// Sum qty * price from object elements
{ $add: [
"$$value",
{ $multiply: [ "$$this.qty", "$$this.price" ] }
]} input — the array to fold (field path like "$scores" or a literal array).initialValue — starting accumulator (e.g. 0 for sum, "" for concat).in — expression that returns the new accumulator each step.$$value — current accumulator; $$this — current element.initialValue without running in.input is null or missing, $reduce returns null.$project, $addFields, or $set.$reduce → folds array into one value (sum, max, custom logic)$map → transforms each element; output is a new array$sum in $group → aggregates across documents, not within one array field$reduce = array.reduce(), $map = array.map()| Question | Answer |
|---|---|
| Operator type | Aggregation array expression operator |
| Syntax | { $reduce: { input, initialValue, in } } |
| Accumulator | $$value |
| Current element | $$this |
| Empty array | Returns initialValue |
{
$reduce: {
input: "$scores",
initialValue: 0,
in: {
$add: ["$$value","$$this"]
}
}
}Total of scores
{
$reduce: {
input: "$scores",
initialValue: null,
in: {
$max: ["$$value","$$this"]
}
}
}Highest score
{
$reduce: {
input: "$tags",
initialValue: "",
in: {
$concat: ["$$value","$$this"]
}
}
}Join strings
initialValue: 0
// input: [] → 0Returns initial
Sum student scores, total order line items, find the maximum value, and concatenate tag strings with $reduce.
Fold a scores array into a single total with $project.
Suppose you have a students collection:
[
{
"_id": 1,
"name": "Alice",
"scores": [70, 85, 90]
},
{
"_id": 2,
"name": "Bob",
"scores": [60, 75, 80]
}
] Add all values in the scores array:
db.students.aggregate([
{
$project: {
name: 1,
totalScore: {
$reduce: {
input: "$scores",
initialValue: 0,
in: { $add: [ "$$value", "$$this" ] }
}
}
}
}
]) 0 + 70 = 7070 + 85 = 155155 + 90 = 245 (final result for Alice)Order totals from object arrays, maximum values, and string concatenation.
Sum qty × price across an array of item objects:
db.orders.aggregate([
{
$project: {
orderId: 1,
orderTotal: {
$reduce: {
input: "$items",
initialValue: 0,
in: {
$add: [
"$$value",
{ $multiply: [ "$$this.qty", "$$this.price" ] }
]
}
}
}
}
}
])
// items: [{ qty: 2, price: 10 }, { qty: 1, price: 25 }]
// orderTotal: 45 When array elements are objects, access fields on $$this: $$this.qty and $$this.price. Each step adds the line total to the running sum.
Use $max inside in to track the highest value:
db.students.aggregate([
{
$project: {
name: 1,
topScore: {
$reduce: {
input: "$scores",
initialValue: null,
in: { $max: [ "$$value", "$$this" ] }
}
}
}
}
]) Starting with null, $max compares the accumulator with each element. The final $$value is the largest number in the array.
Join an array of strings into one comma-separated label:
db.products.aggregate([
{
$project: {
name: 1,
tagLabel: {
$reduce: {
input: "$tags",
initialValue: "",
in: {
$cond: [
{ $eq: [ "$$value", "" ] },
"$$this",
{ $concat: [ "$$value", ", ", "$$this" ] }
]
}
}
}
}
}
])
// tags: ["sale", "new", "featured"]
// tagLabel: "sale, new, featured" The $cond avoids a leading comma on the first element. For the first tag, output just $$this; afterward, prepend ", ".
Compute the sum of 1 through 5 using a generated sequence:
db.samples.aggregate([
{
$project: {
sumOneToFive: {
$reduce: {
input: { $range: [1, 6] },
initialValue: 0,
in: { $add: [ "$$value", "$$this" ] }
}
}
}
}
])
// sumOneToFive: 15 (1+2+3+4+5) $range creates [1, 2, 3, 4, 5]; $reduce folds it into a single sum. Pair sequence generators with $reduce for indexed calculations.
items arrays.$min or $max in in.$reduce WorksMongoDB sets $$value to initialValue before processing the first element.
For every item, $$this is the current element and in returns the new accumulator.
After the last element, the accumulator becomes the single output value stored in your projected field.
Arrays collapse into totals, extremes, or custom aggregates per document.
The $reduce operator folds arrays into single values in MongoDB aggregation pipelines. With input, initialValue, and in, you can sum, find maxima, concatenate strings, or implement any custom fold logic over embedded arrays.
Remember $$value is the accumulator and $$this is the current element. Empty arrays return initialValue. Next in the series: $regex.
initialValue that matches your goal (0 for sum, "" for concat)$$value and $$this inside in$$this.fieldName$range for sequence-based folds$sum in $group when aggregating across documents$$value with single-$ field paths$reduce when $map needs an array outputinitialValueinitialValue (it is required)null input behaves like an empty array (it returns null)$reduceUse these points when folding arrays in aggregation pipelines.
Many → one value.
Purposeinput, initial, in.
SyntaxAcc + current.
VariablesCommon folds.
Use caseReturns initial.
Edge caseMove on to $regex for pattern matching, or review $map for element-wise transforms.
5 people found this page helpful