> For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt

# $reduce (expression operator)

## Definition

Applies an expression to each element in an array and combines them into a single value.

[`$reduce`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reduce.md#mongodb-expression-exp.-reduce) has the following syntax:

```javascript
{
    $reduce: {
        input: <array expression>,
        initialValue: <expression>,
        in: <expression>,
        as: <string>,
        valueAs: <string>,
        arrayIndexAs: <string>
    }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `input` | array | Can be any valid [expression](https://www.mongodb.com/docs/manual/reference/mql/expressions.md#std-label-aggregation-expressions) that resolves to an array. For more information on expressions, see [Expressions.](https://www.mongodb.com/docs/manual/reference/mql/expressions.md#std-label-aggregation-expressions) If  the argument resolves to a value of `null` or refers to a missing field, [`$reduce`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reduce.md#mongodb-expression-exp.-reduce) returns `null`. If the argument does not resolve to an array or `null` nor refers to a missing field, [`$reduce`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reduce.md#mongodb-expression-exp.-reduce) returns an error. |
| `initialValue` | expression | The initial cumulative `value` set before `in` is applied to the first element of the `input` array. |
| `in` | expression | A valid [expression](https://www.mongodb.com/docs/manual/reference/mql/expressions.md#std-label-aggregation-expressions) that `$reduce` applies to each element in the `input` array in left-to-right order. Wrap the `input` value with [`$reverseArray`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reversearray.md#mongodb-expression-exp.-reverseArray) to yield the equivalent of applying the combining expression from right-to-left. During evaluation of the `in` expression, two variables will be available: `value` is the [variable](https://www.mongodb.com/docs/manual/reference/aggregation-variables.md#std-label-aggregation-variables) that represents the cumulative value of the expression.; `this` is the [variable](https://www.mongodb.com/docs/manual/reference/aggregation-variables.md#std-label-aggregation-variables) that refers to the element being processed. |
| `as` | string | Optional. A name for the variable that represents each individual element of the `input` array. If omitted, the variable name defaults to `this`. **New in version 8.3** |
| `valueAs` | string | Optional. A name for the variable that represents the cumulative value of the expression. If omitted, the variable name defaults to `value`. **New in version 8.3** |
| `arrayIndexAs` | string | Optional. A name for the [aggregation variable](https://www.mongodb.com/docs/manual/reference/aggregation-variables.md#std-label-aggregation-variables) that represents the index of the current element in the `input` array. The first array element index is `0`. You can use the variable name in an expression. For example, if you specify `arrayIndexAs: "myIndex"`, you use `$$myIndex` in the expression. `$$myIndex` returns the index of the current element in the `input` array. If you omit `arrayIndexAs`, you can use the [`$$IDX`](https://www.mongodb.com/docs/manual/reference/aggregation-variables.md#mongodb-variable-variable.IDX) system variable in the expression to return the index of the current element. For examples, see [Access the Index of Each Item in an Array](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reduce.md#std-label-reduce-index-example) and [Use `$$IDX` to Access the Index.](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reduce.md#std-label-reduce-IDX-example) **New in version 8.3** |

If `input` resolves to an empty array, [`$reduce`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reduce.md#mongodb-expression-exp.-reduce) returns `initialValue`.

| Example | Results |
| --- | --- |
| ` {
    $reduce: {
       input: ["a", "b", "c"],
       initialValue: "",
       in: { $concat : ["$$value", "$$this"] }
     }
 }` | `"abc"` |
| `{
   $reduce: {
      input: [ 1, 2, 3, 4 ],
      initialValue: { sum: 5, product: 2 },
      in: {
         sum: { $add : ["$$value.sum", "$$this"] },
         product: { $multiply: [ "$$value.product", "$$this" ] }
      }
   }
}` | `{ "sum" : 15, "product" : 48 }` |
| `{
   $reduce: {
      input: [ [ 3, 4 ], [ 5, 6 ] ],
      initialValue: [ 1, 2 ],
      in: { $concatArrays : ["$$value", "$$this"] }
   }
}` | `[ 1, 2, 3, 4, 5, 6 ]` |

## Examples

### Multiplication

#### Probability

A collection named `events` contains the events of a probability experiment. Each experiment can have multiple `events`, such as rolling a die several times or drawing several cards **(without replacement)** in succession to achieve a desired result. In order to obtain the overall probability of the experiment, we will need to multiply the probability of each event in the experiment.

```javascript
db.events.insertMany( [
   { _id : 1, type : "die", experimentId :"r5", description : "Roll a 5", eventNum : 1, probability : 0.16666666666667 },
   { _id : 2, type : "card", experimentId :"d3rc", description : "Draw 3 red cards", eventNum : 1, probability : 0.5 },
   { _id : 3, type : "card", experimentId :"d3rc", description : "Draw 3 red cards", eventNum : 2, probability : 0.49019607843137 },
   { _id : 4, type : "card", experimentId :"d3rc", description : "Draw 3 red cards", eventNum : 3, probability : 0.48 },
   { _id : 5, type : "die", experimentId :"r16", description : "Roll a 1 then a 6", eventNum : 1, probability : 0.16666666666667 },
   { _id : 6, type : "die", experimentId :"r16", description : "Roll a 1 then a 6", eventNum : 2, probability : 0.16666666666667 },
   { _id : 7, type : "card", experimentId :"dak", description : "Draw an ace, then a king", eventNum : 1, probability : 0.07692307692308 },
   { _id : 8, type : "card", experimentId :"dak", description : "Draw an ace, then a king", eventNum : 2, probability : 0.07843137254902 }
] )
```

**Steps**:

1. Use `$group` to group by the `experimentId` and use `$push` to create an array with the probability of each event.

2. Use `$reduce` with `$multiply` to multiply and combine the elements of `probabilityArr` into a single value and project it.

```javascript
db.probability.aggregate(
  [
    {
      $group: {
        _id: "$experimentId",
        probabilityArr: { $push: "$probability" }
      }
    },
    {
      $project: {
        description: 1,
        results: {
          $reduce: {
            input: "$probabilityArr",
            initialValue: 1,
            in: { $multiply: [ "$$value", "$$this" ] }
          }
        }
      }
    }
  ]
)
```

The operation returns the following:

```javascript
{ _id : "dak", results : 0.00603318250377101 }
{ _id : "r5", results : 0.16666666666667 }
{ _id : "r16", results : 0.027777777777778886 }
{ _id : "d3rc", results : 0.11764705882352879 }
```

#### Discounted Merchandise

A collection named `clothes` contains the following documents:

```javascript
db.clothes.insertMany( [
   { _id : 1, productId : "ts1", description : "T-Shirt", color : "black", size : "M", price : 20, discounts : [ 0.5, 0.1 ] },
   { _id : 2, productId : "j1", description : "Jeans", color : "blue", size : "36", price : 40, discounts : [ 0.25, 0.15, 0.05 ] },
   { _id : 3, productId : "s1", description : "Shorts", color : "beige", size : "32", price : 30, discounts : [ 0.15, 0.05 ] },
   { _id : 4, productId : "ts2", description : "Cool T-Shirt", color : "White", size : "L", price : 25, discounts : [ 0.3 ] },
   { _id : 5, productId : "j2", description : "Designer Jeans", color : "blue", size : "30", price : 80, discounts : [ 0.1, 0.25 ] }
] )
```

Each document contains a `discounts` array containing the currently available percent-off coupons for each item. If each discount can be applied to the product once, we can calculate the lowest price by using `$reduce` to apply the following formula for each element in the `discounts` array: (1 - discount) \* price.

```javascript
db.clothes.aggregate(
  [
    {
      $project: {
        discountedPrice: {
          $reduce: {
            input: "$discounts",
            initialValue: "$price",
            in: { $multiply: [ "$$value", { $subtract: [ 1, "$$this" ] } ] }
          }
        }
      }
    }
  ]
)
```

The operation returns the following:

```javascript
{ _id : ObjectId("57c893067054e6e47674ce01"), discountedPrice : 9 }
{ _id : ObjectId("57c9932b7054e6e47674ce12"), discountedPrice : 24.224999999999998 }
{ _id : ObjectId("57c993457054e6e47674ce13"), discountedPrice : 24.224999999999998 }
{ _id : ObjectId("57c993687054e6e47674ce14"), discountedPrice : 17.5 }
{ _id : ObjectId("57c993837054e6e47674ce15"), discountedPrice : 54 }
```

### String Concatenation

A collection named `people` contains the following documents:

```javascript
db.people.insertMany( [
   { _id : 1, name : "Melissa", hobbies : [ "softball", "drawing", "reading" ] },
   { _id : 2, name : "Brad", hobbies : [ "gaming", "skateboarding" ] },
   { _id : 3, name : "Scott", hobbies : [ "basketball", "music", "fishing" ] },
   { _id : 4, name : "Tracey", hobbies : [ "acting", "yoga" ] },
   { _id : 5, name : "Josh", hobbies : [ "programming" ] },
   { _id : 6, name : "Claire" }
] )
```

The following example reduces the `hobbies` array of strings into a single string `bio`:

```javascript
db.people.aggregate(
   [
     // Filter to return only non-empty arrays
     { $match: { "hobbies": { $gt: [ ] } } },
     {
       $project: {
         name: 1,
         bio: {
           $reduce: {
             input: "$hobbies",
             initialValue: "My hobbies include:",
             in: {
               $concat: [
                 "$$value",
                 {
                   $cond: {
                     if: { $eq: [ "$$value", "My hobbies include:" ] },
                     then: " ",
                     else: ", "
                   }
                 },
                 "$$this"
               ]
             }
           }
         }
       }
     }
   ]
)
```

The operation returns the following:

```javascript
{ _id : 1, name : "Melissa", bio : "My hobbies include: softball, drawing, reading" }
{ _id : 2, name : "Brad", bio : "My hobbies include: gaming, skateboarding" }
{ _id : 3, name : "Scott", bio : "My hobbies include: basketball, music, fishing" }
{ _id : 4, name : "Tracey", bio : "My hobbies include: acting, yoga" }
{ _id : 5, name : "Josh", bio : "My hobbies include: programming" }
```

### Array Concatenation

A collection named `matrices` contains the following documents:

```javascript
db.matrices.insertMany( [
   { _id : 1, arr : [ [ 24, 55, 79 ], [ 14, 78, 35 ], [ 84, 90, 3 ], [ 50, 89, 70 ] ] },
   { _id : 2, arr : [ [ 39, 32, 43, 7 ], [ 62, 17, 80, 64 ], [ 17, 88, 11, 73 ] ] },
   { _id : 3, arr : [ [ 42 ], [ 26, 59 ], [ 17 ], [ 72, 19, 35 ] ] },
   { _id : 4 }
] )
```

#### Computing a Single Reduction

The following example collapses the two dimensional arrays into a single array `collapsed`:

```javascript
db.arrayconcat.aggregate(
  [
    {
      $project: {
        collapsed: {
          $reduce: {
            input: "$arr",
            initialValue: [ ],
            in: { $concatArrays: [ "$$value", "$$this" ] }
          }
        }
      }
    }
  ]
)
```

The operation returns the following:

```javascript
{ _id : 1, collapsed : [ 24, 55, 79, 14, 78, 35, 84, 90, 3, 50, 89, 70 ] }
{ _id : 2, collapsed : [ 39, 32, 43, 7, 62, 17, 80, 64, 17, 88, 11, 73 ] }
{ _id : 3, collapsed : [ 42, 26, 59, 17, 72, 19, 35 ] }
{ _id : 4, collapsed : null }
```

#### Computing a Multiple Reductions

The following example performs the same two dimensional array collapse as the example above, but also creates a new array containing only the first element of each array.

```javascript
db.arrayconcat.aggregate(
  [
    {
      $project: {
        results: {
          $reduce: {
            input: "$arr",
            initialValue: [ ],
            in: {
              collapsed: {
                $concatArrays: [ "$$value.collapsed", "$$this" ]
              },
              firstValues: {
                $concatArrays: [ "$$value.firstValues", { $slice: [ "$$this", 1 ] } ]
              }
            }
          }
        }
      }
    }
  ]
)
```

The operation returns the following:

```javascript
{ _id : 1, results : { collapsed : [ 24, 55, 79, 14, 78, 35, 84, 90, 3, 50, 89, 70 ], firstValues : [ 24, 14, 84, 50 ] } }
{ _id : 2, results : { collapsed : [ 39, 32, 43, 7, 62, 17, 80, 64, 17, 88, 11, 73 ], firstValues : [ 39, 62, 17 ] } }
{ _id : 3, results : { collapsed : [ 42, 26, 59, 17, 72, 19, 35 ], firstValues : [ 42, 26, 17, 72 ] } }
{ _id : 4, results : null }
```

### Access the Index of Each Item in an Array

Create a sample collection named `people` with these documents:

```javascript
db.people.insertMany( [
   { _id: 1, name: "Melissa", hobbies: [ "softball", "drawing", "reading" ] },
   { _id: 2, name: "Brad", hobbies: [ "gaming", "skateboarding" ] },
   { _id: 3, name: "Scott", hobbies: [ "basketball", "music", "fishing" ] },
   { _id: 4, name: "Tracey", hobbies: [ "acting", "yoga" ] },
   { _id: 5, name: "Josh", hobbies: [ "programming" ] },
   { _id: 6, name: "Claire" }
] )
```

The `hobbies` field contains an array of each person's hobbies in ranked order. The first hobby in the array is the person's primary hobby that the person spends the most time on. The first hobby has an array index of `0`.

The following example uses `valueAs`, `as`, and `arrayIndexAs`. The `myIndex` variable has the index of each hobby in the `hobbies` array. The example returns documents with these fields:

- Person name.

- `text` field, which includes the hobby name and the position of each hobby in the list.

```javascript
db.people.aggregate( [
   {
      $project: {
         _id: 0,
         name: 1,
         text: {
            $reduce: {
               input: "$hobbies",
               initialValue: "My hobbies include:",
               valueAs: "accumulatedText",
               as: "hobby",
               arrayIndexAs: "myIndex",
               in: {
                  $concat: [
                     "$$accumulatedText",
                     " ",
                     { $toString: { $add: [ "$$myIndex", 1 ] } },
                     ") ",
                     "$$hobby"
                  ]
               }
            }
         }
      }
   }
] )
```

Output:

```javascript
[
   { "name" : "Melissa", "text" : "My hobbies include: 1) softball 2) drawing 3) reading" }
   { "name" : "Brad", "text" : "My hobbies include: 1) gaming 2) skateboarding" }
   { "name" : "Scott", "text" : "My hobbies include: 1) basketball 2) music 3) fishing" }
   { "name" : "Tracey", "text" : "My hobbies include: 1) acting 2) yoga" }
   { "name" : "Josh", "text" : "My hobbies include: 1) programming" }
   { "name" : "Claire", "text" : null }
]
```

### Use `$$IDX` to Access the Index

The [`$$IDX`](https://www.mongodb.com/docs/manual/reference/aggregation-variables.md#mongodb-variable-variable.IDX) variable returns the index of the current element in the `input` array. You can use `$$IDX` if you omit the `arrayIndexAs` field from the expression.

The following example returns the same documents as the example in the previous section [Access the Index of Each Item in an Array](https://www.mongodb.com/docs/manual/reference/operator/aggregation/reduce.md#std-label-reduce-index-example), but uses `$$IDX` instead of `arrayIndexAs`:

```javascript
db.people.aggregate( [
   {
      $project: {
         _id: 0,
         name: 1,
         text: {
            $reduce: {
               input: "$hobbies",
               initialValue: "My hobbies include:",
               valueAs: "accumulatedText",
               as: "hobby",
               in: {
                  $concat: [
                     "$$accumulatedText",
                     " ",
                     { $toString: { $add: [ "$$IDX", 1 ] } },
                     ") ",
                     "$$hobby"
                  ]
               }
            }
         }
      }
   }
] )
```
