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

<!--
Tab options on this page. Append to the .md URL to filter:
  ?tabs=<id,...>   select specific tabs (e.g. ?tabs=nodejs,shell)
  ?allTabs=true    include every tab
  (no param)       default: one tab per tabset

Available tabs:
  drivers: shell, csharp, nodejs
-->

# $unwind (aggregation stage)

## Definition

Deconstructs an array field from the input documents to output a document for *each* element. Each output document is the input document with the value of the array field replaced by the element.

## Compatibility

You can use `$unwind` for deployments hosted in the following environments:

- [MongoDB Atlas](https://www.mongodb.com/docs/atlas): The fully managed service for MongoDB deployments in the cloud

* [MongoDB Enterprise](https://www.mongodb.com/docs/manual/administration/install-enterprise.md#std-label-install-mdb-enterprise): The subscription-based, self-managed version of MongoDB

* [MongoDB Community](https://www.mongodb.com/docs/manual/administration/install-community.md#std-label-install-mdb-community-edition): The source-available, free-to-use, and self-managed version of MongoDB

## Syntax

Pass a field path operand or a document operand to unwind an array field.

### Field Path Operand

You can pass the array field path to `$unwind`. With this syntax, `$unwind` does not output a document if the field value is null, missing, or an empty array.

```javascript
{ $unwind: <field path> }
```

When you specify the field path, prefix the field name with a dollar sign `$` and enclose in quotes.

### Document Operand with Options

You can pass a document to `$unwind` to specify options.

```javascript
{
  $unwind:
    {
      path: <field path>,
      includeArrayIndex: <string>,
      preserveNullAndEmptyArrays: <boolean>
    }
}
```

| Field | Type | Description |
| --- | --- | --- |
| [path](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-unwind-path) | string | Field path to an array field. To specify a field path, prefix the field name with a dollar sign `$` and enclose in quotes. |
| [includeArrayIndex](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-unwind-includeArrayIndex) | string | Optional. The name of a new field to hold the array index of the element. The name cannot start with a dollar sign `$`. |
| [preserveNullAndEmptyArrays](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-unwind-preserveNullAndEmptyArrays) | boolean | Optional. If `true`, if `path` is missing or is an empty array, `$unwind` omits the output field from the output document. If the value is `null`, the field remains `null`.; If `false`, if `path` is null, missing, or an empty array, `$unwind` does not output a document. The default value is `false`. |

## Behaviors

### Non-Array Field Path

When the value at `path` does not resolve to an array, `$unwind` behaves as follows:

- If the value is not missing, not `null`, and not an empty array, `$unwind` outputs a single document using the value as-is.

- If `includeArrayIndex` is specified, the index is `0` for array inputs and `null` for non-array inputs. Documents later in the list have an index greater than `0`.

- If the value is missing, `null`, or an empty array, `$unwind` follows the [preserveNullAndEmptyArrays](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-unwind-preserveNullAndEmptyArrays) option. When `includeArrayIndex` is specified and the document is preserved, the index is `null`.

### Missing Field

If you specify a path for a field that does not exist in an input document or the field is an empty array, `$unwind`, by default, ignores the input document and will not output documents for that input document.

To output documents where the array field is missing, null, or an empty array, use the [preserveNullAndEmptyArrays](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-unwind-preserveNullAndEmptyArrays) option.

## Examples

### MongoDB Shell

The examples on this page use data from the [sample\_mflix dataset](https://www.mongodb.com/docs/manual/sample-data/sample-mflix.md#std-label-sample-mflix). For details on how to load this dataset into your self-managed MongoDB deployment, see [Load the Sample Dataset](https://www.mongodb.com/docs/manual/sample-data/load-sample-data-local.md#std-label-sample-dataset-local). If you made any modifications to the sample databases, you may need to drop and recreate the databases to run the examples on this page.

### Unwind Array

The following aggregation uses the `$unwind` stage to output a document for each element in the `genres` array of the `Inception` movie document:

```javascript
db.movies.aggregate( [
  { $match: { title: "Inception" } },
  { $project: { _id: 0, title: 1, genres: 1 } },
  { $unwind: "$genres" }
] )

```

**Output:**

```javascript
[
  {
    genres: 'Action',
    title: 'Inception'
  },
  {
    genres: 'Mystery',
    title: 'Inception'
  },
  {
    genres: 'Sci-Fi',
    title: 'Inception'
  }
]

```

Each output document is identical to the input document except for the value of the `genres` field, which now holds a single element from the original `genres` array.

### Missing or Non-array Values

The following aggregation uses the `$unwind` stage with four movie documents. Two of the documents (`"La porta del cielo"` and `"Neecha Nagar"`) do not have a `genres` field:

```javascript
db.movies.aggregate( [
  {
    $match: {
      title: {
        $in: [
          "Inception",
          "Brave",
          "La porta del cielo",
          "Neecha Nagar"
        ]
      }
    }
  },
  { $project: { _id: 0, title: 1, genres: 1 } },
  { $unwind: { path: "$genres" } }
] )

```

**Output:**

```javascript
[
  {
    genres: 'Animation',
    title: 'Brave'
  },
  {
    genres: 'Adventure',
    title: 'Brave'
  },
  {
    genres: 'Comedy',
    title: 'Brave'
  },
  {
    genres: 'Action',
    title: 'Inception'
  },
  {
    genres: 'Mystery',
    title: 'Inception'
  },
  {
    genres: 'Sci-Fi',
    title: 'Inception'
  }
]

```

- In the `"Brave"` and `"Inception"` documents, `genres` is a populated array. `$unwind` returns a document for each element.

- The `"La porta del cielo"` and `"Neecha Nagar"` documents do not have a `genres` field, so `$unwind` does not return any documents for them.

**Note:**

The `{ path: <FIELD> }` syntax is optional. The following `$unwind` operations are equivalent.

```javascript
db.<COLLECTION>.aggregate(
  [ { $unwind: "<FIELD>" } ]
)
```

```javascript
db.<COLLECTION>.aggregate(
  [ { $unwind: { path: "<FIELD>" } } ]
)
```

### preserveNullAndEmptyArrays and includeArrayIndex

The [preserveNullAndEmptyArrays](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-ex-preservedNull) and [includeArrayIndex](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-ex-includeArrayIndex) examples use documents from the `sample_mflix.movies` collection.

#### preserveNullAndEmptyArrays

The following `$unwind` operation uses the [preserveNullAndEmptyArrays](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-unwind-preserveNullAndEmptyArrays) option to include documents whose `genres` field is missing.

```javascript
db.movies.aggregate( [
  {
    $match: {
      title: {
        $in: [
          "Inception",
          "Brave",
          "La porta del cielo",
          "Neecha Nagar"
        ]
      }
    }
  },
  { $project: { _id: 0, title: 1, genres: 1 } },
  {
    $unwind: {
      path: "$genres",
      preserveNullAndEmptyArrays: true
    }
  }
] )

```

**Output:**

```javascript
[
  {
    title: 'La porta del cielo'
  },
  {
    title: 'Neecha Nagar'
  },
  {
    genres: 'Animation',
    title: 'Brave'
  },
  {
    genres: 'Adventure',
    title: 'Brave'
  },
  {
    genres: 'Comedy',
    title: 'Brave'
  },
  {
    genres: 'Action',
    title: 'Inception'
  },
  {
    genres: 'Mystery',
    title: 'Inception'
  },
  {
    genres: 'Sci-Fi',
    title: 'Inception'
  }
]

```

#### includeArrayIndex

The following `$unwind` operation uses the [includeArrayIndex](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind.md#std-label-unwind-includeArrayIndex) option to include the array index in the output.

```javascript
db.movies.aggregate( [
  { $match: { title: "Inception" } },
  { $project: { _id: 0, title: 1, genres: 1 } },
  {
    $unwind: {
      path: "$genres",
      includeArrayIndex: "genreIndex"
    }
  }
] )

```

**Output:**

```javascript
[
  {
    genres: 'Action',
    title: 'Inception',
    genreIndex: Long('0')
  },
  {
    genres: 'Mystery',
    title: 'Inception',
    genreIndex: Long('1')
  },
  {
    genres: 'Sci-Fi',
    title: 'Inception',
    genreIndex: Long('2')
  }
]

```

### Group by Unwound Values

The following pipeline unwinds the `genres` array and groups the resulting documents by genre to count the number of movies in each genre:

```javascript
db.movies.aggregate( [
  // First Stage
  {
    $match: {
      title: {
        $in: [
          "The Dark Knight",
          "Inception",
          "Interstellar",
          "Brave"
        ]
      }
    }
  },
  // Second Stage
  { $project: { _id: 0, title: 1, genres: 1 } },
  // Third Stage
  { $unwind: "$genres" },
  // Fourth Stage
  {
    $group: {
      _id: "$genres",
      movieCount: { $sum: 1 }
    }
  },
  // Fifth Stage
  { $sort: { movieCount: -1 } }
] )

```

**Output:**

```javascript
[
  {
    _id: 'Adventure',
    movieCount: 2
  },
  {
    _id: 'Action',
    movieCount: 2
  },
  {
    _id: 'Drama',
    movieCount: 2
  },
  {
    _id: 'Sci-Fi',
    movieCount: 2
  },
  {
    _id: 'Crime',
    movieCount: 1
  },
  {
    _id: 'Animation',
    movieCount: 1
  },
  {
    _id: 'Comedy',
    movieCount: 1
  },
  {
    _id: 'Mystery',
    movieCount: 1
  }
]

```

### Unwind Multiple Array Fields

You can apply `$unwind` multiple times in a single pipeline to expand documents that contain several array fields. The following operation unwinds the `genres` array and then the `cast` array to produce a flat document for every genre-actor combination, then groups by genre to count the total cast appearances in each genre:

```javascript
db.movies.aggregate( [
  // First Stage
  {
    $match: {
      title: {
        $in: [ "Inception", "The Dark Knight", "Interstellar" ]
      }
    }
  },
  // Second Stage
  { $project: { _id: 0, title: 1, genres: 1, cast: 1 } },
  // Third Stage
  { $unwind: "$genres" },
  // Fourth Stage
  { $unwind: "$cast" },
  // Fifth Stage
  {
    $group: {
      _id: "$genres",
      castAppearances: { $sum: 1 }
    }
  }
] )

```

**Output:**

```javascript
[
  {
    _id: 'Adventure',
    castAppearances: 4
  },
  {
    _id: 'Crime',
    castAppearances: 4
  },
  {
    _id: 'Action',
    castAppearances: 8
  },
  {
    _id: 'Drama',
    castAppearances: 8
  },
  {
    _id: 'Mystery',
    castAppearances: 4
  },
  {
    _id: 'Sci-Fi',
    castAppearances: 8
  }
]

```

## Learn More

For related stages and expressions, see [`$group`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/group.md#mongodb-pipeline-pipe.-group), [`$sum`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/sum.md#mongodb-group-grp.-sum), [`$sort`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/sort.md#mongodb-pipeline-pipe.-sort), and [`$multiply`.](https://www.mongodb.com/docs/manual/reference/operator/aggregation/multiply.md#mongodb-expression-exp.-multiply)

For a full example, see the [Unwind Arrays and Group Data](https://www.mongodb.com/docs/manual/tutorial/aggregation-examples/unpack-arrays.md#std-label-agg-example-unpack-arrays) tutorial.
