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

# `facet` (MongoDB Search Operator)

## Definition

The `facet` collector groups results by values or ranges in the specified faceted fields and returns the count for each of those groups.

You can use `facet` with both the [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) and [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stages. MongoDB recommends using `facet` with the [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stage to retrieve metadata results only for the query. To retrieve metadata results and query results using the [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) stage, you must use the `$$SEARCH_META` aggregation variable. See [`SEARCH_META` Aggregation Variable](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-aggregation-variable) to learn more.

If you define [storedSource](https://www.mongodb.com/docs/search/indexes/stored-source-definition.md#std-label-fts-stored-source-definition) in your [embeddedDocuments](https://www.mongodb.com/docs/search/indexes/field-types/embedded-documents-type.md#std-label-bson-data-types-embedded-documents) field type definition, you can use [returnScope](https://www.mongodb.com/docs/search/query/return-scope.md#std-label-fts-return-scope) with [returnStoredSource](https://www.mongodb.com/docs/search/query/return-stored-source.md#std-label-fts-return-stored-source-option) to facet on nested fields inside an array of objects. Otherwise, you can only facet on the root [embeddedDocuments](https://www.mongodb.com/docs/search/indexes/field-types/embedded-documents-type.md#std-label-bson-data-types-embedded-documents) type field. For an example of faceting on:

- Nested fields inside an array of objects, see [returnScope Example.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-egs)

- Matching children of an `embeddedDocuments` array using `embeddedDocument`, see [Embedded-Scoped Facet Example.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-embedded-scoped-egs)

- Root `embeddedDocuments` type field, see [Facet Query.](https://www.mongodb.com/docs/search/query/operators-collectors/embedded-document.md#std-label-embedded-document-query-examples)

## Syntax

`facet` has the following syntax:

```javascript
{
  "$searchMeta"|"$search": {
    "index": <index name>, // optional, defaults to "default"
    "facet": {
      "operator": {
        <operator-specifications>
      },
      "facets": {
        <facet-definitions>
      }
    },
    "returnScope": {
      "path": "<embedded-documents-field-to-query>"
    },
    "returnStoredSource": true
  }
}
```

## Fields

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `facets` | document | yes | [Information](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-definition) for bucketing the data for each facet. You must specify at least one [Facet Definition](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-definition). Each facet definition can also specify [Facet Aggregations](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-aggregation) to compute metrics for each bucket. |
| `operator` | document | no | [Operator](https://www.mongodb.com/docs/search/query/operators-collectors/overview.md#std-label-operators-ref) to use to perform the facet over. If omitted, MongoDB Search performs the facet over all documents in the collection. |

## Memory Requirements

Facet queries are memory-intensive, regardless of your cluster tier. Queries that specify [Facet Aggregations](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-aggregation) or [nested facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-nested) require more memory and disk than other facet queries. Before you use facets in production, confirm that your cluster has enough memory for your workload. To learn more, see [Search Memory Management](https://www.mongodb.com/docs/search/performance/index-performance.md#std-label-fts-search-memory-management). To get sizing guidance for your workload, [request support.](https://www.mongodb.com/docs/atlas/support.md#std-label-atlas-support)

The memory that a facet query requires depends on the number of unique values in the field that you facet on, not the number of buckets that you request using `numBuckets` or `boundaries`. For example, a facet that requests `20` buckets on a field with five million unique values still counts every unique value to determine the top `20` buckets.

For [nested facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-nested), the total unique values computed in a query multiply based on the unique values across each level of nesting. Even when each individual field has low cardinality, the combination of values across nested paths can produce a large number of unique buckets. To learn more about how nested facets multiply buckets, see [Nested Facets.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-nested)

MongoDB Search tracks bucket counts separately for each query, so total memory use scales with the number of concurrent facet queries. On a sharded cluster, MongoDB Search also requires memory to merge the buckets from each shard, which scales with the number of shards and the number of buckets.

## Facet Definition

The facet definition document contains the facet name and options specific to a type of facet. MongoDB Search supports the following types of facets:

- [String Facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-string-facet)

- [Numeric Facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-numeric-facet)

- [Date Facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-date-facet)

### String Facets

**Important:**

[stringFacet](https://www.mongodb.com/docs/search/indexes/field-types/string-facet-type.md#std-label-bson-data-types-string-facet) is now outdated. Use [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) instead, which provides improved faceting.

To learn more about the differences between the updated and outdated field types for facet, see [Comparing Field Types for Facet.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-type-differences)

String facets allow you to narrow down MongoDB Search results based on the most frequent string values in the specified string field. The string field must be indexed as [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token). To facet on string fields in embedded documents, you must also index the parent fields as the [document](https://www.mongodb.com/docs/search/indexes/field-types/document-type.md#std-label-bson-data-types-document) type. When you facet on strings in arrays or embedded documents, MongoDB Search returns facet counts based on the number of matching root documents.

#### Syntax

String facets have the following syntax:

```json
{
  "$searchMeta": {
    "facet":{
      "operator": {
        <operator-specification>
      },
      "facets": {
        "<facet-name>" : {
          "type" : "string",
          "path" : "<field-path>",
          "numBuckets" : <number-of-categories>,
          "embeddedDocument": { <embedded-document-scope> } // optional
        }
      }
    }
  }
}
```

#### Options

| Option | Type | Description | Required? |
| --- | --- | --- | --- |
| `embeddedDocument` | object | Scopes the facet's bucket counts to only the child documents of an `embeddedDocuments` array that match a query predicate. To learn more, see [Facet on Matching Children of an Embedded Documents Array.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-embedded-scoped) | no |
| `numBuckets` | int | Maximum number of facet categories to return in the results. Value must be less than or equal to `10000`. If specified, MongoDB Search may return fewer categories than requested if the data is grouped into fewer categories than your requested number. If omitted, defaults to `10`, which means that MongoDB Search returns only the top `10` facet categories by count. | no |
| `path` | string | Field path to facet on. You can specify a field that is indexed as a [token.](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) | yes |
| `type` | string | Type of facet. Value must be `string`. | yes |

#### Example

**Example:**

The following example uses an index named `default` on the `sample_mflix.movies` collection. The `genres` field in the collection is indexed as the [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) type and the `year` field is indexed as the [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) type.

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "genres": {
        "type": "token"
      },
      "year": {
        "type": "number"
      }
    }
  }
}
```

The query uses the [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stage to search the `year` field in the `movies` collection for movies from 2000 to 2015 and retrieve a count of the number of movies in each genre.

```shell
db.movies.aggregate([
  {
    "$searchMeta": {
      "facet": {
        "operator": {
          "range": {
            "path": "year",
            "gte": 2000,
            "lte": 2015
          }
        },
        "facets": {
          "genresFacet": {
            "type": "string",
            "path": "genres"
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('12568') },
    facet: {
      genresFacet: {
        buckets: [
          { _id: 'Drama', count: Long('7079') },
          { _id: 'Comedy', count: Long('3689') },
          { _id: 'Romance', count: Long('1764') },
          { _id: 'Thriller', count: Long('1584') },
          { _id: 'Documentary', count: Long('1472') },
          { _id: 'Action', count: Long('1471') },
          { _id: 'Crime', count: Long('1367') },
          { _id: 'Adventure', count: Long('1056') },
          { _id: 'Horror', count: Long('866') },
          { _id: 'Biography', count: Long('796') }
        ]
      }
    }
  }
]
```

To learn more about these results, see [Facet Results.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-results)

### Numeric Facets

**Important:**

[numberFacet](https://www.mongodb.com/docs/search/indexes/field-types/number-facet-type.md#std-label-bson-data-types-number-facet) is now outdated. Use [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) instead, which provides improved faceting.

To learn more about the differences between the updated and outdated field types for facet, see [Comparing Field Types for Facet.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-type-differences)

Numeric facets allow you to determine the frequency of numeric values in your search results by breaking the results into separate ranges of numbers. When you facet on numbers in arrays or embedded documents, MongoDB Search returns facet counts based on the number of matching root documents.

#### Syntax

Numeric facets have the following syntax:

```json
{
  "$searchMeta": {
    "facet":{
      "operator": {
        <operator-specification>
      },
      "facets": {
        "<facet-name>" : {
          "type" : "number",
          "path" : "<field-path>",
          "boundaries" : <array-of-numbers>,
          "default": "<bucket-name>",
          "embeddedDocument": { <embedded-document-scope> } // optional
        }
      }
    }
  }
}
```

#### Options

| Option | Type | Description | Required? |
| --- | --- | --- | --- |
| `boundaries` | array of numbers | List of numeric values in ascending order that specify the boundaries for your buckets. You must specify between two and ten thousand (`[2, 10000]`) boundary values. Each adjacent pair of values defines a bucket with an inclusive lower bound and an exclusive upper bound. You can specify any combination of values of the following [BSON types:](https://www.mongodb.com/docs/manual/reference/bson-types.md#std-label-bson-types) 32-bit integer (`int32`); 64-bit integer (`int64`); 64-bit binary floating point (`double`) | yes |
| `default` | string | Name of an additional bucket that counts documents returned from the operator that do not fall within the specified boundaries. If omitted, MongoDB Search includes the results of the facet operator that do not fall under a specified bucket also, but doesn't include it in any bucket counts. | no |
| `embeddedDocument` | object | Scopes the facet's bucket counts to only the child documents of an `embeddedDocuments` array that match a query predicate. To learn more, see [Facet on Matching Children of an Embedded Documents Array.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-embedded-scoped) | no |
| `path` | string | Field path to facet on. You can specify a field that is indexed as the [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) type. | yes |
| `type` | string | Type of facet. Value must be `number`. | yes |

#### Example

**Example:**

The following example uses an index named `default` on the `sample_mflix.movies` collection. The `year` field in the collection is indexed as the [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) type.

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "year": [
        {
          "type": "number"
        }
      ]
    }
  }
}
```

The query uses the [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stage to search the `year` field in the `movies` collection for movies between the years `1980` and `2000` and retrieve metadata results for the query. The query specifies three buckets:

- `1980`, inclusive lower bound for this bucket

- `1990`, exclusive upper bound for the `1980` bucket and inclusive lower bound for this bucket

- `2000`, exclusive upper bound for the `1990` bucket

The query also specifies a `default` bucket named `other` to retrieve results of the query that don't fall under any of the specified boundaries.

```json
db.movies.aggregate([
  {
    "$searchMeta": {
      "facet": {
        "operator": {
         "range": {
            "path": "year",
            "gte": 1980,
            "lte": 2000
          }
        },
        "facets": {
          "yearFacet": {
            "type": "number",
            "path": "year",
            "boundaries": [1980,1990,2000],
            "default": "other"
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('6095') },
    facet: {
      yearFacet: {
        buckets: [
          { _id: 1980, count: Long('1956') },
          { _id: 1990, count: Long('3558') },
          { _id: 'other', count: Long('581') }
        ]
      }
    }
  }
]
```

To learn more about these results, see [Facet Results.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-results)

### Date Facets

**Important:**

[dateFacet](https://www.mongodb.com/docs/search/indexes/field-types/date-facet-type.md#std-label-bson-data-types-date-facet) is now outdated. Use [date](https://www.mongodb.com/docs/search/indexes/field-types/date-type.md#std-label-bson-data-types-date) instead, which provides improved faceting.

To learn more about the differences between the updated and outdated field types for facet, see [Comparing Field Types for Facet.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-type-differences)

Date facets allow you to narrow down search results based on a date. When you facet on dates in arrays or embedded documents, MongoDB Search returns facet counts based on the number of matching root documents.

#### Syntax

Date facets have the following syntax:

```json
{
  "$searchMeta": {
    "facet":{
      "operator": {
        <operator-specification>
      },
      "facets": {
        "<facet-name>" : {
          "type" : "date",
          "path" : "<field-path>",
          "boundaries" : <array-of-dates>,
          "default": "<bucket-name>",
          "embeddedDocument": { <embedded-document-scope> } // optional
        }
      }
    }
  }
}
```

#### Options

| Option | Type | Description | Required? |
| --- | --- | --- | --- |
| `boundaries` | array of numbers | List of date values that specify the boundaries for each bucket. You must specify: At least two boundaries, which are less than or equal to ten thousand (`[2, 10000]`); Values in ascending order, with the earliest date first Each adjacent pair of values acts as the inclusive lower bound and the exclusive upper bound for the bucket. | yes |
| `default` | string | Name of an additional bucket that counts documents returned from the operator that do not fall within the specified boundaries. If omitted, MongoDB Search includes the results of the facet operator that do not fall under a specified bucket also, but MongoDB Search doesn't include these results in any bucket counts. | no |
| `embeddedDocument` | object | Scopes the facet's bucket counts to only the child documents of an `embeddedDocuments` array that match a query predicate. To learn more, see [Facet on Matching Children of an Embedded Documents Array.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-embedded-scoped) | no |
| `path` | string | Field path to facet on. You can specify a field that is indexed as a [date](https://www.mongodb.com/docs/search/indexes/field-types/date-type.md#std-label-bson-data-types-date) type. | yes |
| `type` | string | Type of facet. Value must be `date`. | yes |

#### Example

**Example:**

The following example uses an index named `default` on the `sample_mflix.movies` collection. The `released` field in the collection is indexed as the [date](https://www.mongodb.com/docs/search/indexes/field-types/date-type.md#std-label-bson-data-types-date) type.

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "released": [
        {
          "type": "date"
        }
      ]
    }
  }
}
```

The query uses the [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stage to search the `released` field in the `movies` collection for movies between the years `2000` and `2015` and retrieve metadata results for the query. The query specifies four buckets:

- `2000-01-01`, inclusive lower bound for this bucket

- `2005-01-01`, exclusive upper bound for the `2000-01-01` bucket and inclusive lower bound for this bucket

- `2010-01-01`, exclusive upper bound for the `2005-01-01` bucket and inclusive lower bound for this bucket

- `2015-01-01`, exclusive upper bound for the `2010-01-01` bucket

The query also specifies a `default` bucket named `other` to retrieve results of the query that don't fall under any of the specified boundaries.

```json
db.movies.aggregate([
  {
    "$searchMeta": {
      "facet": {
        "operator": {
          "range": {
            "path": "released",
            "gte": ISODate("2000-01-01T00:00:00.000Z"),
            "lte": ISODate("2015-01-31T00:00:00.000Z")
          }
        },
        "facets": {
          "yearFacet": {
            "type": "date",
            "path": "released",
            "boundaries": [ISODate("2000-01-01"), ISODate("2005-01-01"), ISODate("2010-01-01"), ISODate("2015-01-01")],
            "default": "other"
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('11922') },
    facet: {
      yearFacet: {
        buckets: [
          {
            _id: ISODate('2000-01-01T00:00:00.000Z'),
            count: Long('3028')
          },
          {
            _id: ISODate('2005-01-01T00:00:00.000Z'),
            count: Long('3953')
          },
          {
            _id: ISODate('2010-01-01T00:00:00.000Z'),
            count: Long('4832')
          },
          { _id: 'other', count: Long('109') }
        ]
      }
    }
  }
]
```

To learn more about these results, see [Facet Results.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-results)

### Comparing Field Types for Facet

The updated MongoDB Search field types provide improved functionality to support faceting compared to the outdated types (`stringFacet`, `numberFacet`, `dateFacet`). The following table outlines the key differences in functionality:

| Facet Category | Updated Field Type | Outdated Facet Type | Key Differences |
| --- | --- | --- | --- |
| String | [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) | [stringFacet](https://www.mongodb.com/docs/search/indexes/field-types/string-facet-type.md#std-label-bson-data-types-string-facet) (outdated) | **Normalizer Support**: The `token` type supports normalizers that transform facet buckets. For example, with `normalizer: lowercase`, "ADIDAS" and "adidas" count toward the same bucket while `stringFacet` treats them as separate buckets. |
| Numeric | [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) | [numberFacet](https://www.mongodb.com/docs/search/indexes/field-types/number-facet-type.md#std-label-bson-data-types-number-facet) (outdated) | **Array Support**: The `number` type considers values within arrays for facet buckets. For example, a document with an array value `[0, 10]` counts toward both buckets `[1, 5]` and `[6, 10]` while `numberFacet` ignores array values completely. |
| Date | [date](https://www.mongodb.com/docs/search/indexes/field-types/date-type.md#std-label-bson-data-types-date) | [dateFacet](https://www.mongodb.com/docs/search/indexes/field-types/date-facet-type.md#std-label-bson-data-types-date-facet) (outdated) | **Array Support**: The `date` type considers values within arrays for facet buckets. For example, an array value with dates can contribute to multiple date range buckets while `dateFacet` ignores array values completely. |

**Note:**

When both the outdated and updated field types are defined for the same field, the outdated facet types take precedence. For example, if both `token` and `stringFacet` are defined for a field, the facet calculation uses the `stringFacet` mapping.

### Facet on Matching Children of an Embedded Documents Array

Each facet definition can include an optional `embeddedDocument` field that scopes the facet's bucket counts to only the child documents in an [embeddedDocuments](https://www.mongodb.com/docs/search/indexes/field-types/embedded-documents-type.md#std-label-bson-data-types-embedded-documents) array that match a query predicate. If you omit the `embeddedDocument` field, the facet is document-indexed.

Without `embeddedDocument`, a root document counts in a bucket if it has any child document that falls into that bucket, even if that child doesn't match the query defined in the `facet.operator` block. The `embeddedDocument` field restricts bucket contributions to only the children that match the specified `embeddedDocument.operator`. It counts each root document at most once per bucket.

The `embeddedDocument` field takes the following fields:

| Field | Type | Description | Required? |
| --- | --- | --- | --- |
| `path` | string | Indexed `embeddedDocuments` type field to scope the facet into. The facet's `path` must be a descendant of this field. | yes |
| `operator` | object | [Operator](https://www.mongodb.com/docs/search/query/operators-collectors/overview.md#std-label-operators-ref) to run against each child document in the `embeddedDocuments` array that you specify in `path`. Only child documents that match this operator contribute to the facet's bucket counts. Every path referenced in this operator must be a descendant of `path`. | yes |

For a [number](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-numeric-facet) or [date](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-date-facet) facet, a matching child whose value falls outside the configured `boundaries` counts in the `default` bucket, if you specify one, using the same rule as a document-indexed facet. A root document with no matching child doesn't contribute to the `embeddedDocument`-scoped facet, but can still contribute to any other, unscoped facet in the same query.

**Important:**

You can't combine an `embeddedDocument`-scoped facet with several other faceting options. To learn more, see [Limitations.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-limitations)

For an example, see the [Embedded-Scoped Facet Example.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-embedded-scoped-egs)

## Facet Aggregations

**Important:**

Facet aggregations is in Preview. The feature and corresponding documentation might change at any time during the Preview period. To learn more, see [Preview Features.](https://www.mongodb.com/docs/preview-features/)

To compute metrics for each facet bucket, add an `aggregations` document to a facet definition. MongoDB Search computes the metrics from the MongoDB Search index, so it is much more efficient than running a [`$group`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/group.md#mongodb-pipeline-pipe.-group) stage later in your pipeline.

For each facet bucket, `aggregations` allows you to compute the following values:

- sum

- average

- minimum

- maximum

- first

- last

When using `aggregations`, you must:

- Index the field that you specify in the `path` for each metric as `token`, `number`, or `date`.

- Explicitly include the `count` metric if you want the bucket count.

- Only specify `aggregations` at the leaf-level of nested facets.

  If you want to compute metrics for an intermediate grouping, specify that grouping as a separate top-level facet with `aggregations` and no nested facet.

MongoDB Search computes `aggregations` over the data in the MongoDB Search index, which is [eventually consistent.](https://www.mongodb.com/docs/search/performance/index-performance.md#std-label-index-perf)

**Note: Memory Requirements**

Facet queries that specify `aggregations` or [nested facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-nested) increase the memory and disk that your MongoDB Search index requires beyond the requirements for other facet queries. To learn more, see [Memory Requirements.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-memory)

### Syntax

`aggregations` has the following syntax:

```javascript
{
  "$searchMeta": {
    "facet": {
      "facets": {
        "<facet-name>": {
          "type": "<facet-type>",
          "path": "<field-path>",
          "aggregations": {
            "<aggregation-name>": {
              "type": "sum" | "min" | "max" | "avg" | "first" | "last",
              "path": "<field-path>"
            }
          }
        }
      }
    }
  }
}
```

Each key in the `aggregations` document is an aggregation name that you specify. MongoDB Search returns each aggregation in the bucket documents under the name that you specify.

### Options

| Option | Type | Description | Required? |
| --- | --- | --- | --- |
| `path` | string | Field path to compute the metric over. This is required for all metric types except `count`, which doesn't accept a `path`. Every other metric type computes a value from a second field, so you must name that field. For example, to return the average rating of the documents in a bucket, specify `avg` with a `path` of `rating`. The `count` metric counts the documents in the bucket, so it doesn't need a second field. | conditional |
| `type` | string | Type of metric to compute. Value can be one of the following: `count`; `sum`; `avg`; `min`; `max`; `first`; `last` To learn more about each metric type, see [Metric Types.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-metric-types) | yes |

### Metric Types

| Type | Field Requirements | Description |
| --- | --- | --- |
| `count` | None | Counts the documents in the bucket. Don't specify a `path` for this metric type. If you omit `aggregations` from a facet definition, MongoDB Search returns a `count` metric for the bucket. If you specify `aggregations`, MongoDB Search returns a `count` metric only if you specify `count` in the `aggregations` document. |
| `sum` | [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) | Adds the values of the specified field for the documents in the bucket. |
| `avg` | [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) | Returns the average of the values of the specified field for the documents in the bucket. If no document in the bucket has a value for the field, MongoDB Search returns `null`. |
| `min` | None | Returns the lowest value of the specified field for the documents in the bucket. |
| `max` | None | Returns the highest value of the specified field for the documents in the bucket. |
| `first` | None | Returns the value of the specified field for the first document in the bucket, according to the order that the query [sort](https://www.mongodb.com/docs/search/query/sort.md#std-label-sort-ref) option defines. If the query doesn't specify a sort, the order is arbitrary. To learn how to specify a sort, see [Sort MongoDB Search Results.](https://www.mongodb.com/docs/search/query/sort.md#std-label-sort-ref) |
| `last` | None | Returns the value of the specified field for the last document in the bucket, according to the order that the query [sort](https://www.mongodb.com/docs/search/query/sort.md#std-label-sort-ref) option defines. If the query doesn't specify a sort, the order is arbitrary. To learn how to specify a sort, see [Sort MongoDB Search Results.](https://www.mongodb.com/docs/search/query/sort.md#std-label-sort-ref) |

**Important:**

`min` and `max` support all field types, including `token`. When MongoDB Search computes these metrics, it skips any document in which the field resolves to an unsupported type. MongoDB Search doesn't return an error when it skips a document. To determine whether MongoDB Search skipped documents in a bucket, add a `count` metric to the same `aggregations` document and compare it to the number of documents that you expect.

For values that MongoDB Search doesn't skip, `min` selects the smallest value in the bucket and `max` selects the largest. If the values aren't all of the same type, MongoDB Search applies [BSON type comparison order](https://www.mongodb.com/docs/manual/reference/bson-type-comparison-order.md#std-label-bson-types-comparison-order) to determine which value is smallest or largest.

#### Array Considerations

Each metric type handles a field that resolves to more than one value, such as an array, differently:

- `sum` and `avg` skip the document.

- `min` and `max` select the lowest and highest value in the array to use as a representative element for the document.

- `first` and `last` return all of the values as an array.

For `first` and `last`, the returned array differs from the source document in the following ways:

- The order of the values might differ. MongoDB Search reads the values from the index, which doesn't preserve the order of the source document. For example, if a document contains `["red", "blue", "green"]`, MongoDB Search might return `["blue", "green", "red"]`.

- MongoDB Search returns only one instance of a duplicate value.

- MongoDB Search returns every value at the path, including values of a type that you can't facet on. For example, if an array contains both strings and a boolean, MongoDB Search returns the boolean with the strings.

To return the values exactly as the source document contains them, define [storedSource](https://www.mongodb.com/docs/search/indexes/stored-source-definition.md#std-label-fts-stored-source-definition) for the field in your index definition and set [returnStoredSource](https://www.mongodb.com/docs/search/query/return-stored-source.md#std-label-fts-return-stored-source-option) to `true` in your query.

## Nested Facets

**Important:**

Nested facets is in Preview. The feature and corresponding documentation might change at any time during the Preview period. To learn more, see [Preview Features.](https://www.mongodb.com/docs/preview-features/)

To group the documents in each bucket by additional fields, add a `facets` document to an existing facet definition. Each nested facet definition uses the same syntax as a top-level facet definition, so you can nest facets to build a tree of groupings. MongoDB Search returns the buckets for a nested facet inside each bucket of its parent facet.

For each bucket of a facet that contains a nested facet, MongoDB Search also returns a `count` field with the number of documents in the bucket. You don't need to specify a `count` metric for these intermediate buckets.

You can nest facets without limit on the number of levels. However, the following restrictions apply:

- You can specify `aggregations` only on a leaf facet in a nested facet tree. A facet definition that specifies `facets` can't also specify `aggregations`. To compute metrics for an intermediate grouping, specify that grouping as a separate top-level facet with `aggregations` and no nested facet.

- You can't name a nested facet `count`. MongoDB Search reserves `count` for the document count of intermediate buckets.

- The total number of unique buckets that a query can return can't exceed `100000`. To calculate the buckets that one facet tree produces, multiply the number of buckets at each level of its nesting branch. The number of buckets at a level is `numBuckets` for a string facet or the number of buckets that `boundaries` and `default` define for a number or date facet. For example, a facet that requests `20` buckets and contains a nested facet that requests `20` buckets produces `400` unique buckets. Because each level multiplies this total, requesting more buckets at each level reduces the number of levels that you can nest.

## Facet Results

For a facet query, MongoDB Search returns a mapping of the defined facet names to an array of buckets for that facet in the results. The facet result document contains the `buckets` option, which is an array of resulting buckets for the facet. Each facet bucket document in the array has the following fields:

| Option | Type | Description |
| --- | --- | --- |
| `_id` | object | Unique identifier that identifies this facet bucket. This value matches the type of data that is being faceted on. |
| `count` | int | Count of documents in this facet bucket. To learn more about the `count` field, see [Count MongoDB Search Results.](https://www.mongodb.com/docs/search/query/counting.md#std-label-count-ref) |

If the facet definition specifies [Facet Aggregations](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-aggregation), each bucket document contains the metrics that you name in the `aggregations` document instead of the `count` field. If the facet definition specifies [nested facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-nested), each bucket document contains a `count` field with the number of documents in the bucket, and the results for the nested facet.

## Multi-Select Facets

MongoDB Search allows you to view and select multiple buckets within the same facet simultaneously. Typically, selecting a bucket within a facet filters search results according to that selection and alters counts for all facets.

**Example:**

Suppose an index definition for the `sample_airbnb.listings` collection specifies facets for the following fields:

- `cancellation_policy`

- `room_type`

- `accommodates`

The `cancellation_policy` facet has the following buckets:

- `flexible`

- `moderate`

- `strict_14_with_grace_period`

- `super_strict_30`

- `super_strict_60`

Each bucket has its own result count. When you search for the `moderate` `cancellation_policy`, the counts for the four other buckets go to `0`. Additionally, the counts for buckets in the `room_type` and `accommodates` facets reduce to the number of results in each bucket that also have a `flexible` `cancellation_policy`.

In scenarios where you need more granular control of how facets affect search result counts, enable multi-select faceting with the `doesNotAffect` property in your faceted queries. These facets still filter results, but the query doesn't alter their result counts.

You can specify `doesNotAffect` in the following operators:

- [compound](https://www.mongodb.com/docs/search/query/operators-collectors/compound.md#std-label-compound-ref)

- [equals](https://www.mongodb.com/docs/search/query/operators-collectors/equals.md#std-label-equals-ref)

- [in](https://www.mongodb.com/docs/search/query/operators-collectors/in.md#std-label-in-ref)

- [range](https://www.mongodb.com/docs/search/query/operators-collectors/range.md#std-label-range-ref)

To exclude multiple facets, specify an array of facet names. Most use cases exclude only the facet that shares a path with the filter. For example, an `equals` filter on the `rating` field specifies the name of the facet that uses `rating` as its path.

**Note:**

The `doesNotAffect` option doesn't work with facets that specify [aggregations](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-aggregation). To learn more, see [Limitations.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-limitations)

**Example:**

Consider a query against the `sample_airbnb.listingsAndReviews` collection for documents with a `moderate` `cancellation_policy`. If you specify a `doesNotAffect` value of `cancellation_policy`, the counts for buckets in the `cancellation_policy` facet don't change, but the result counts for the buckets of other facets reduce to the number of results in each bucket that also have a `moderate` `cancellation_policy`.

For more information, see the [Multi-Select Faceting example.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-egs)

You can't combine `doesNotAffect` with an `embeddedDocument`-scoped facet. To learn more, see [Facet on Matching Children of an Embedded Documents Array.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-embedded-scoped)

Finally, for use cases with many facets, you can limit which other filters affect a given facet. You can do this by specifying any facet in the `doesNotAffect` property of any filter, including facets on other fields. This allows you to observe at a glance which selections narrow options more or less quickly.

**Example:**

Consider a query against the `sample_airbnb.listingsAndReviews` collection for documents with an `accommodates` value of `3`. If you specify a `doesNotAffect` value of `cancellation_policy`, the result counts for the `room_type` buckets reduce to the number of results in each bucket that also accommodate `3` people, but the result counts for the buckets in `cancellation_policy` are unaffected.

For more information, see the [Inter-Facet Filter Exclusion example.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-egs)

## `SEARCH_META` Aggregation Variable

When you run your query using the [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) stage, MongoDB Search stores the metadata results in the `$$SEARCH_META` variable and returns only the search results. You can use the `$$SEARCH_META` variable in all the supported [aggregation pipeline stages](https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/) to view the metadata results for your [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) query. You can also use the `$$SEARCH_META` variable with [facet.aggregations.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-aggregation)

MongoDB recommends using the `$$SEARCH_META` variable only if you need both the search results and the metadata results. Otherwise, use the:

- [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) stage for just the search results.

- [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stage for just the metadata results.

## Limitations

You can run facet queries on a single field only. You can't run facet queries on groups of fields.

### Limitations for Embedded-Scoped Facets

The following limitations apply to [Facet on Matching Children of an Embedded Documents Array:](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-embedded-scoped)

- You can't combine a top-level `returnScope` option with an `embeddedDocument`-scoped facet in the same query.

- An `embeddedDocument`-scoped facet returns only a count.

- You can't combine drill-sideways faceting (`doesNotAffect`) with an `embeddedDocument`-scoped facet in the same query.

### Limitations for Facet Aggregations

The following limitations apply to [Facet Aggregations:](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-aggregation)

- You can't use the following options with `aggregations`:

  - [returnScope](https://www.mongodb.com/docs/search/query/return-scope.md#std-label-fts-return-scope)

  - `doesNotAffect` for [Multi-Select Facets](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-multi-select)

- You can't facet or compute aggregations on the following [BSON types:](https://www.mongodb.com/docs/manual/reference/bson-types.md#std-label-bson-types)

  - `binData`

  - `bool`

  - `decimal`

  - `null`

  - `objectId`

  - `timestamp`

  To compute metrics over one of these types, use a [view](https://www.mongodb.com/docs/manual/core/views.md#std-label-views-landing-page) to convert the field to a supported type before you index it.

## Examples

The following examples use the [sample data](https://www.mongodb.com/docs/atlas/import/load-sample-data.md#std-label-sample-data). The metadata results example demonstrates how to run a [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) query with `facet` to retrieve only the metadata in the results. The metadata and search results example demonstrates how to run a [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) query with `facet` and the `$SEARCH_META` aggregation variable to retrieve both the search and metadata results. The `returnScope` example demonstrates how to facet on nested fields in an array of objects dynamically indexed using the `embeddedDocuments` type. The embedded-scoped facet example demonstrates how to facet on only the matching children of an `embeddedDocuments` array. The multi-select and inter-facet filter exclusion examples demonstrate how to use `doesNotAffect` to control how facets affect each other's counts. The aggregation example demonstrates how to compute metrics for each facet bucket, and the nested facet example demonstrates how to group results by a second field and compute metrics for each bucket.

### Metadata Results Example

#### Complete the previous steps in the tutorial and install dependencies

The index definition on the `sample_mflix.movies` collection specifies the following for the fields to index:

| Field Name | Data Type |
| --- | --- |
| `directors` | [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) |
| `year` | [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) |
| `released` | [date](https://www.mongodb.com/docs/search/indexes/field-types/date-type.md#std-label-bson-data-types-date) |

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "directors": {
        "type": "token"
      },
      "year": {
        "type": "number"
      },
      "released": {
        "type": "date"
      }
    }
  }
}
```

The following query searches for movies released between January 01, 2000 and January 31, 2015. It requests metadata on the `directors` and `year` fields.

```json
db.movies.aggregate([
  {
    "$searchMeta": {
      "facet": {
        "operator": {
          "range": {
            "path": "released",
            "gte": ISODate("2000-01-01T00:00:00.000Z"),
            "lte": ISODate("2015-01-31T00:00:00.000Z")
          }
        },
        "facets": {
          "directorsFacet": {
            "type": "string",
            "path": "directors",
            "numBuckets" : 7
          },
          "yearFacet" : {
            "type" : "number",
            "path" : "year",
            "boundaries" : [2000,2005,2010, 2015]
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('11922') },
    facet: {
      yearFacet: {
        buckets: [
          { _id: 2000, count: Long('3064') },
          { _id: 2005, count: Long('4035') },
          { _id: 2010, count: Long('4553') }
        ]
      },
      directorsFacet: {
        buckets: [
          { _id: 'Takashi Miike', count: Long('26') },
          { _id: 'Johnnie To', count: Long('20') },
          { _id: 'Steven Soderbergh', count: Long('18') },
          { _id: 'Michael Winterbottom', count: Long('16') },
          { _id: 'Ridley Scott', count: Long('15') },
          { _id: 'Tyler Perry', count: Long('15') },
          { _id: 'Clint Eastwood', count: Long('14') }
        ]
      }
    }
  }
]
```

The results show a count of the following in the `sample_mflix.movies` collection:

- Number of movies from the year 2000, inclusive lower bound, to 2015, exclusive upper bound, that MongoDB Search returned for the query

- Number of movies for each director that MongoDB Search returned for the query

To learn more about these results, see [Facet Results.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-results)

### Metadata and Search Results Example

#### Search using $search and retrieve both search and metadata results using $$SEARCH\_META variable.

The index definition on the `sample_mflix.movies` collection specifies the following for the fields to index:

| Field Name | Data Type |
| --- | --- |
| `genres` | [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) |
| `released` | [date](https://www.mongodb.com/docs/search/indexes/field-types/date-type.md#std-label-bson-data-types-date) |

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "genres": {
        "type": "token"
      },
      "released": {
        "type": "date"
      }
    }
  }
}
```

The following query searches for movies released near July 01, 1999 using the [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) stage. The query includes a [`$facet`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/facet.md#mongodb-pipeline-pipe.-facet) stage to process the input documents using the following sub-pipeline stages:

- [`$project`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/project.md#mongodb-pipeline-pipe.-project) stage to exclude all fields in the documents except the `title` and `released` fields in the `docs` output field

- [`$limit`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/limit.md#mongodb-pipeline-pipe.-limit) stage to do the following:

  - Limit the `$search` stage output to `2` documents

  - Limit the output to `1` document in the `meta` output field

  **Note:**

  The limit must be small for the results to fit in a 16 MB document.

- [`$replaceWith`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/replaceWith.md#mongodb-pipeline-pipe.-replaceWith) stage to include the metadata results stored in the `$$SEARCH_META` variable in the `meta` output field

The query also includes a [`$set`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/set.md#mongodb-pipeline-pipe.-set) stage to add the `meta` field.

**Note:**

To see the metadata results for the following query, MongoDB Search must return documents that match the query.

```json
db.movies.aggregate([
 {
   "$search": {
     "facet": {
       "operator": {
         "near": {
           "path": "released",
           "origin": ISODate("1999-07-01T00:00:00.000+00:00"),
           "pivot": 7776000000
         }
       },
       "facets": {
         "genresFacet": {
           "type": "string",
           "path": "genres"
         }
       }
     }
   }
 },
 { "$limit": 2 },
 {
   "$facet": {
     "docs": [
       { "$project":
         {
           "title": 1,
           "released": 1
         }
       }
     ],
     "meta": [
       {"$replaceWith": "$$SEARCH_META"},
       {"$limit": 1}
     ]
   }
 },
 {
   "$set": {
     "meta": {
       "$arrayElemAt": ["$meta", 0]
     }
   }
 }
])
```

**Output:**

```shell
[
 {
   docs: [
     {
       _id: ObjectId('573a1393f29313caabcde1ae'),
       title: 'Begone Dull Care',
       released: ISODate('1999-07-01T00:00:00.000Z')
     },
     {
       _id: ObjectId('573a13a9f29313caabd2048a'),
       title: 'Fara'                released: ISODate('1999-07-01T00:00:00.000Z')
     }
   ],
   meta: {
     count: { lowerBound: Long('20878') },
     facet: {
       genresFacet: {
         buckets: [
           { _id: 'Drama', count: Long('12149') },
           { _id: 'Comedy', count: Long('6436') },
           { _id: 'Romance', count: Long('3274') },
           { _id: 'Crime', count: Long('2429') },
           { _id: 'Thriller', count: Long('2400') },
           { _id: 'Action', count: Long('2349') },
           { _id: 'Adventure', count: Long('1876') },
           { _id: 'Documentary', count: Long('1755') },
           { _id: 'Horror', count: Long('1432') },
           { _id: 'Biography', count: Long('1244') }
         ]
       }
     }
   }
 }
]
```

To learn more about these results, see [Facet Results.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-results)

### returnScope Example

#### Search using facet and facet on child fields in embeddedDocuments.

The index definition on the `sample_training.companies` collection indexes the `funding_rounds` field as the [embeddedDocuments](https://www.mongodb.com/docs/search/indexes/field-types/embedded-documents-type.md#std-label-bson-data-types-embedded-documents) type. It dynamically indexes all fields in the `funding_rounds` array of objects and stores the `raised_currency_code` and `raised_amount` fields in the `funding_rounds` array of objects using the [storedSource](https://www.mongodb.com/docs/search/indexes/stored-source-definition.md#std-label-fts-stored-source-definition) option.

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "funding_rounds": {
        "type": "embeddedDocuments",
        "dynamic": true,
        "storedSource": {
          "include": [
            "raised_currency_code",
            "raised_amount"
          ]
        }
      }
    }
  }
}
```

The following query:

- Uses the [`text` (MongoDB Search Operator)](https://www.mongodb.com/docs/search/query/operators-collectors/text.md#std-label-text-ref) to search for funds raised in `USD`.

- Uses [returnScope](https://www.mongodb.com/docs/search/query/return-scope.md#std-label-fts-return-scope) options to set the query context to the `embeddedDocuments` field named `funding_rounds`. To use `returnScope`, the query:

  - Specifies the [returnStoredSource](https://www.mongodb.com/docs/search/query/return-stored-source.md#std-label-fts-return-stored-source-option) option, which is required, to return the stored source fields.

- Facets on the `raised_amount` field in the `funding_rounds` array of objects. The query specifies three buckets:

  - 5000000, inclusive lower bound for this bucket

  - 5250000, exclusive upper bound for the 5000000 bucket and inclusive lower bound for this bucket

  - 5500000, exclusive upper bound for the 5250000 bucket

```json
db.companies.aggregate([
 {
   "$searchMeta": {
     "returnStoredSource": true,
     "returnScope": {
       "path": "funding_rounds"
     },
     "facet": {
       "operator": {
         "text": {
           "path": "funding_rounds.raised_currency_code",
           "query": "USD"
         }
       },
       "facets": {
         "raisedAmountFacet": {
           "type": "number",
           "path": "funding_rounds.raised_amount",
           "boundaries": [5000000, 5250000, 5500000]
         }
       }
     }
   }
 }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('5329') },
    facet: {
      raisedAmountFacet: {
        buckets: [
          { _id: 5000000, count: Long('251') },
          { _id: 5250000, count: Long('32') }
        ]
      }
    }
  }
]
```

In the preceding MongoDB Search results, the facet counts are based on the embedded child documents and not the parents.

### Embedded-Scoped Facet Example

#### Facet on only the matching children of an embeddedDocuments array.

The index definition on the `sample_training.companies` collection indexes the `funding_rounds` field as the [embeddedDocuments](https://www.mongodb.com/docs/search/indexes/field-types/embedded-documents-type.md#std-label-bson-data-types-embedded-documents) type, with the `round_code` and `raised_currency_code` fields in each funding round indexed as [token.](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token)

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "name": {
        "type": "token"
      },
      "funding_rounds": {
        "type": "embeddedDocuments",
        "dynamic": false,
        "fields": {
          "round_code": {
            "type": "token"
          },
          "raised_currency_code": {
            "type": "token"
          }
        }
      }
    }
  }
}
```

`KickApps`, `Topix`, and `StumbleUpon` each have several funding rounds, only some of which were raised in `USD`:

```json
// KickApps
{ "name": "KickApps",
  "funding_rounds": [
    { "round_code": "a", "raised_currency_code": "USD" },
    { "round_code": "b", "raised_currency_code": "USD" },
    { "round_code": "c", "raised_currency_code": "GBP" }
  ]
}
// Topix
{ "name": "Topix",
  "funding_rounds": [
    { "round_code": "a", "raised_currency_code": null },
    { "round_code": "b", "raised_currency_code": "USD" }
  ]
}
// StumbleUpon
{ "name": "StumbleUpon",
  "funding_rounds": [
    { "round_code": "seed", "raised_currency_code": "USD" },
    { "round_code": "a", "raised_currency_code": null },
    { "round_code": "b", "raised_currency_code": "USD" },
    { "round_code": "angel", "raised_currency_code": null }
  ]
}
```

The following query uses the [in](https://www.mongodb.com/docs/search/query/operators-collectors/in.md#std-label-in-ref) operator to restrict the facet to these three companies, then facets on `funding_rounds.round_code`. The `roundFacet` definition specifies an `embeddedDocument` block that scopes the facet to only the funding rounds where `raised_currency_code` is `USD`.

```json
db.companies.aggregate([
  {
    "$searchMeta": {
      "facet": {
        "operator": {
          "in": {
            "path": "name",
            "value": ["KickApps", "Topix", "StumbleUpon"]
          }
        },
        "facets": {
          "roundFacet": {
            "type": "string",
            "path": "funding_rounds.round_code",
            "embeddedDocument": {
              "path": "funding_rounds",
              "operator": {
                "equals": {
                  "path": "funding_rounds.raised_currency_code",
                  "value": "USD"
                }
              }
            }
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('3') },
    facet: {
      roundFacet: {
        buckets: [
          { _id: 'b', count: Long('3') },
          { _id: 'a', count: Long('1') },
          { _id: 'seed', count: Long('1') }
        ]
      }
    }
  }
]
```

Each company counts once per round code for which it has at least one funding round raised in `USD`:

- `b` counts `3`: KickApps, Topix, and StumbleUpon each have a `b` round raised in `USD`.

- `a` counts `1`: only KickApps has an `a` round raised in `USD`. Topix's and StumbleUpon's `a` rounds have no recorded currency, so they don't match.

- `seed` counts `1`: StumbleUpon's `seed` round was raised in `USD`.

KickApps' `c` round doesn't contribute to a `c` bucket because it was raised in `GBP`, not `USD`. Without the `embeddedDocument` block, faceting on `funding_rounds.round_code` requires indexing `funding_rounds` as the [document](https://www.mongodb.com/docs/search/indexes/field-types/document-type.md#std-label-bson-data-types-document) type instead, and an unscoped facet would also count KickApps in a `c` bucket, because the root document has a matching child in that bucket regardless of its currency.

### Multi-Select Faceting Example

#### Search with doesNotAffect for more granular control over facet filtering.

The following index definition on the `sample_airbnb.listingsAndReviews` collection automatically indexes all dynamically indexable fields and configures the `cancellation_policy`, `room_type`, and `price` fields for faceted search.

```json
{
  "mappings": {
    "dynamic": true,
    "fields": {
      "cancellation_policy": {
        "type": "token"
      },
      "room_type": {
        "type": "token"
      },
      "accommodates": {
        "type": "number"
      }
    }
  }
}
```

The following query uses the [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stage to perform the following actions:

- Facet on the `cancellation_policy`, `roomType`, and `accommodates` fields.

  The `cancellation_policy` facet has the following buckets:

  - `"strict_14_with_grace_period"`

  - `"moderate"`

  - `"flexible"`

  - `"super_strict_30"`

  - `"super_strict_60"`

  The `room_type` facet has the following buckets:

  - `"Entire home/apt"`

  - `"Private room"`

  - `"Shared room"`

  The query breaks the `accommodates` facet into buckets for:

  - `1`, inclusive lower bound for this bucket

  - `2`, exclusive upper bound for the `1` bucket and inclusive lower bound for this bucket.

  - `4`, exclusive upper bound for the `2` bucket and inclusive lower bound for this bucket.

  - `8`, exclusive upper bound for the `4` bucket

- Perform a [`compound` Operator](https://www.mongodb.com/docs/search/query/operators-collectors/compound.md#std-label-compound-ref) search for listings that *must* contain the text `new york city` in the `description` and *filters* the results for listings with a `moderate` `cancellation_policy`. The `doesNotAffect` setting ensures that filtering by a `moderate` `cancellation_policy` doesn't alter the counts of other buckets in the facet; the counts for `"strict_14_with_grace_period"`, `"flexible"`, `"super_strict_30"`, and `"super_strict_60"` are non-zero values.

```json
db.listingsAndReviews.aggregate([
  {
    $searchMeta: {
      facet: {
        facets: {
          accommodatesFacet: {
            path: "accommodates",
            type: "number",
            boundaries: [1,2,4,8]
          },
          cancellationFacet: {
            path: "cancellation_policy",
            type: "string"
          },
          roomTypeFacet: {
            path: "room_type",
            type: "string"
          }
        },
        operator: {
          compound: {
            must: [
              {
                text: {
                  path: "description",
                  query: "new york city"
                },
              },
            ],
            filter: [
              {
                equals: {
                  path: "cancellation_policy",
                  value: "moderate",
                  doesNotAffect:
                    "cancellationFacet"
                }
              }
            ]
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('531') },
    facet: {
      accommodatesFacet: {
        buckets: [
          { _id: 1, count: Long('25') },
          { _id: 2, count: Long('270') },
          { _id: 4, count: Long('204') }
        ]
      },
      cancellationFacet: {
        buckets: [
          { _id: 'strict_14_with_grace_period', count: Long('849') },
          { _id: 'moderate', count: Long('531') },
          { _id: 'flexible', count: Long('380') },
          { _id: 'super_strict_60', count: Long('25') },
          { _id: 'super_strict_30', count: Long('11') }
        ]
      },
      roomTypeFacet: {
        buckets: [
          { _id: 'Entire home/apt', count: Long('369') },
          { _id: 'Private room', count: Long('159') },
          { _id: 'Shared room', count: Long('3') }
        ]
      }
    }
  }
]
```

The counts for buckets in `cancellationFacet` are not reduced to zero even though the query filters on a value of `moderate`.

### Inter-Facet Filter Exclusion Example

#### Search with doesNotAffect on a facet other than the queried field.

The following index definition on the `sample_airbnb.listingsAndReviews` collection indexes the `cancellation_policy`, `room_type`, and `price` fields, enabling faceted search on them.

```json
{
  "mappings": {
    "dynamic": true,
    "fields": {
      "cancellation_policy": {
        "type": "token"
      },
      "room_type": {
        "type": "token"
      },
      "accommodates": {
        "type": "number"
      }
    }
  }
}
```

The following query:

- Search for listings that include the text `new york city` in their `description` and that have a `cancellation_policy` of `moderate`.

- Facet on the `cancellation_policy`, `roomType`, and `accommodates` fields.

  Each of the `cancellation_policy` and `roomType` facets has three buckets, corresponding to the three unique values of these fields across the collection. The query breaks the `accommodates` facet into buckets for:

  - `1`, inclusive lower bound for this bucket

  - `2`, exclusive upper bound for the `1` bucket and inclusive lower bound for this bucket.

  - `4`, exclusive upper bound for the `2` bucket and inclusive lower bound for this bucket.

  - `8`, exclusive upper bound for the `4` bucket

- Set the `doesNotAffect` property in the `equals` operator of the `compound.filter` to `accommodatesFacet`. This excludes the buckets within the `accommodates` facet from filtering. As a result, filtering on the `moderate` `cancellation_policy` reduces the counts of other buckets in the `cancellation_policy` facet to `0`, and reduces the counts of buckets in the `roomType` facet, but the counts of buckets in the `accommodates` facet are unchanged. This allows you to compare the impact of filtering on different facets.

```json
db.listingsAndReviews.aggregate([
  {
    $searchMeta: {
      facet: {
        facets: {
          accommodatesFacet: {
            path: "accommodates",
            type: "number",
            boundaries: [1,2,4,8],
          },
          cancellationFacet: {
            path: "cancellation_policy",
            type: "string",
          },
          roomTypeFacet: {
            path: "room_type",
            type: "string",
          }
        },
        operator: {
          compound: {
            must: [
              {
                text: {
                  path: "description",
                  query: "new york city",
                },
              },
            ],
            filter: [
              {
                equals: {
                  path: "cancellation_policy",
                  value: "moderate",
                  doesNotAffect:
                    "accommodatesFacet",
                },
              },
            ],
          },
        },
      },
    },
  },
]
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('531') },
    facet: {
      accommodatesFacet: {
        buckets: [
          { _id: 1, count: Long('141') },
          { _id: 2, count: Long('834') },
          { _id: 4, count: Long('703') }
        ]
      },
      cancellationFacet: {
        buckets: [
          { _id: 'moderate', count: Long('531') }
        ]
      },
      roomTypeFacet: {
        buckets: [
          { _id: 'Entire home/apt', count: Long('369') },
          { _id: 'Private room', count: Long('159') },
          { _id: 'Shared room', count: Long('3') }
        ]
      }
    }
  }
]
```

### Aggregation Example

#### Search with facet aggregations.

The following example uses an index named `default` on the `sample_airbnb.listingsAndReviews` collection. The `property_type` and `amenities` fields in the collection are indexed as the [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) type and the `accommodates` field is indexed as the [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) type.

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "property_type": [
        {
          "type": "token"
        }
      ],
      "amenities": [
        {
          "type": "token"
        }
      ],
      "accommodates": [
        {
          "type": "number"
        }
      ]
    }
  }
}
```

The query uses the [`$searchMeta`](https://www.mongodb.com/docs/search/query/aggregation-stages/searchmeta.md#mongodb-pipeline-pipe.-searchMeta) stage to find the listings that offer at least one of the specified amenities and group them by `property_type`. For each property type, the query computes the number of listings and the smallest and largest number of guests that a listing accommodates.

```json
db.listingsAndReviews.aggregate([
  {
    "$searchMeta": {
      "facet": {
        "operator": {
          "in": {
            "path": "amenities",
            "value": ["Wifi", "Pets allowed", "Wheelchair accessible"]
          }
        },
        "facets": {
          "propertyTypeFacet": {
            "type": "string",
            "path": "property_type",
            "aggregations": {
              "listingCount": {
                "type": "count"
              },
              "minAccommodates": {
                "type": "min",
                "path": "accommodates"
              },
            "maxAccommodates": {
                "type": "max",
                "path": "accommodates"
              }
            }
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('5355') },
    facet: {
      propertyTypeFacet: {
        buckets: [
          {
            _id: 'Apartment',
            listingCount: Long('3488'),
            minAccommodates: 1,
            maxAccommodates: 16
          },
          {
            _id: 'House',
            listingCount: Long('584'),
            minAccommodates: 1,
            maxAccommodates: 16
          },
          {
            _id: 'Condominium',
            listingCount: Long('386'),
            minAccommodates: 1,
            maxAccommodates: 12
          },
          {
            _id: 'Serviced apartment',
            listingCount: Long('182'),
            minAccommodates: 1,
            maxAccommodates: 16
          },
          {
            _id: 'Loft',
            listingCount: Long('139'),
            minAccommodates: 1,
            maxAccommodates: 16
          },
          {
            _id: 'Townhouse',
            listingCount: Long('104'),
            minAccommodates: 1,
            maxAccommodates: 16
          },
          {
            _id: 'Guest suite',
            listingCount: Long('79'),
            minAccommodates: 1,
            maxAccommodates: 8
          },
          {
            _id: 'Bed and breakfast',
            listingCount: Long('64'),
            minAccommodates: 1,
            maxAccommodates: 16
          },
          {
            _id: 'Boutique hotel',
            listingCount: Long('51'),
            minAccommodates: 1,
            maxAccommodates: 16
          },
          {
            _id: 'Guesthouse',
            listingCount: Long('49'),
            minAccommodates: 1,
            maxAccommodates: 8
          }
        ]
      }
    }
  }
]
```

### Nested Facet Example

#### Search with nested facets.

The following example uses an index named `default` on the `sample_airbnb.listingsAndReviews` collection. The `property_type` field in the collection is indexed as the [token](https://www.mongodb.com/docs/search/indexes/field-types/token-type.md#std-label-bson-data-types-token) type and the `bedrooms` and `accommodates` fields are indexed as the [number](https://www.mongodb.com/docs/search/indexes/field-types/number-type.md#std-label-bson-data-types-number) type.

```json
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "property_type": [
        {
          "type": "token"
        }
      ],
      "bedrooms": [
        {
          "type": "number"
        }
      ],
      "accommodates": [
        {
          "type": "number"
        }
      ]
    }
  }
}
```

The query groups the listings by `property_type`, and then groups the listings in each property type by number of bedrooms (`0`, `2`, or `4`). The query computes the number of listings and the largest number of guests that a listing accommodates for each bedroom range.

```json
db.listingsAndReviews.aggregate([
  {
    "$searchMeta": {
      "facet": {
        "facets": {
          "propertyTypeFacet": {
            "type": "string",
            "path": "property_type",
            "facets": {
              "bedroomsFacet": {
                "type": "number",
                "path": "bedrooms",
                "boundaries": [0, 2, 4],
                "default": "other",
                "aggregations": {
                  "listingCount": {
                    "type": "count"
                  },
                  "maxAccommodates": {
                    "type": "max",
                    "path": "accommodates"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
])
```

**Output:**

```shell
[
  {
    count: { lowerBound: Long('5555') },
    facet: {
      propertyTypeFacet: {
        buckets: [
          {
            _id: 'Apartment',
            count: { total: Long('3626') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('2534'), maxAccommodates: 12 },
                { _id: 2, listingCount: Long('1006'), maxAccommodates: 13 },
                { _id: 'other', listingCount: Long('86'), maxAccommodates: 16 }
              ]
            }
          },
          {
            _id: 'House',
            count: { total: Long('606') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('312'), maxAccommodates: 16 },
                { _id: 2, listingCount: Long('183'), maxAccommodates: 16 },
                { _id: 'other', listingCount: Long('111'), maxAccommodates: 16 }
              ]
            }
          },
          {
            _id: 'Condominium',
            count: { total: Long('399') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('256'), maxAccommodates: 10 },
                { _id: 2, listingCount: Long('138'), maxAccommodates: 11 },
                { _id: 'other', listingCount: Long('5'), maxAccommodates: 12 }
              ]
            }
          },
          {
            _id: 'Serviced apartment',
            count: { total: Long('185') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('128'), maxAccommodates: 7 },
                { _id: 2, listingCount: Long('53'), maxAccommodates: 12 },
                { _id: 'other', listingCount: Long('4'), maxAccommodates: 16 }
              ]
            }
          },
          {
            _id: 'Loft',
            count: { total: Long('142') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('123'), maxAccommodates: 16 },
                { _id: 2, listingCount: Long('15'), maxAccommodates: 6 },
                { _id: 'other', listingCount: Long('4'), maxAccommodates: 16 }
              ]
            }
          },
          {
            _id: 'Townhouse',
            count: { total: Long('108') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('59'), maxAccommodates: 8 },
                { _id: 2, listingCount: Long('42'), maxAccommodates: 10 },
                { _id: 'other', listingCount: Long('7'), maxAccommodates: 16 }
              ]
            }
          },
          {
            _id: 'Guest suite',
            count: { total: Long('81') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('68'), maxAccommodates: 7 },
                { _id: 2, listingCount: Long('12'), maxAccommodates: 6 },
                { _id: 'other', listingCount: Long('1'), maxAccommodates: 8 }
              ]
            }
          },
          {
            _id: 'Bed and breakfast',
            count: { total: Long('69') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('61'), maxAccommodates: 12 },
                { _id: 2, listingCount: Long('6'), maxAccommodates: 9 },
                { _id: 'other', listingCount: Long('2'), maxAccommodates: 16 }
              ]
            }
          },
          {
            _id: 'Boutique hotel',
            count: { total: Long('53') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('47'), maxAccommodates: 16 },
                { _id: 2, listingCount: Long('5'), maxAccommodates: 6 },
                { _id: 'other', listingCount: Long('1'), maxAccommodates: 15 }
              ]
            }
          },
          {
            _id: 'Guesthouse',
            count: { total: Long('50') },
            bedroomsFacet: {
              buckets: [
                { _id: 0, listingCount: Long('43'), maxAccommodates: 8 },
                { _id: 2, listingCount: Long('7'), maxAccommodates: 6 },
                { _id: 'other', listingCount: Long('0'), maxAccommodates: null }
              ]
            }
          }
        ]
      }
    }
  }
]
```

MongoDB Search returns the following information for each facet bucket:

- The number of listings (`count`) in the bucket (such as `Apartment`, `House`, and so on).

- The maximum number of guests that a listing in the bucket range (`0` bedrooms, `2` bedrooms, and so on) accommodates (`maxAccommodates`).

## Continue Learning

To learn more, see [How to Use Facets with MongoDB Search.](https://www.mongodb.com/docs/search/tutorial/facet-tutorial.md#std-label-facet-tutorial)

You can learn more about [`facet` (MongoDB Search Operator)](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-ref) in MongoDB Search with our [course](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-facet-tutorial-course) and [video.](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-facet-tutorial-video)

### Learn with Courses

To learn more about using facets in MongoDB Search, take Unit 9 of the [Intro To MongoDB Course on MongoDB University](https://learn.mongodb.com/courses/mongodb-atlas-search). The 1.5 hour unit includes an overview of MongoDB Search and lessons on creating MongoDB Search indexes, running [`$search`](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search) queries using compound operators, and grouping results using `facet`.

### Learn by Watching

Watch this video to learn about how you can create and use a numeric and string [`facet` (MongoDB Search Operator)](https://www.mongodb.com/docs/search/query/operators-collectors/facet.md#std-label-fts-facet-ref) in your query to group results and retrieve a count of the results in the groups.

*Duration: 11 Minutes*
