Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
MongoDB Branding Shape
Click here >
Docs Menu

facet (MongoDB Search Operator)

facet

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 and $searchMeta stages. MongoDB recommends using facet with the $searchMeta stage to retrieve metadata results only for the query. To retrieve metadata results and query results using the $search stage, you must use the $$SEARCH_META aggregation variable. See SEARCH_META Aggregation Variable to learn more.

If you define storedSource in your embeddedDocuments field type definition, you can use returnScope with returnStoredSource to facet on nested fields inside an array of objects. Otherwise, you can only facet on the root embeddedDocuments type field. For an example of faceting on:

facet has the following syntax:

{
"$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
}
}
Field
Type
Required?
Description

facets

document

yes

Information for bucketing the data for each facet. You must specify at least one Facet Definition.

operator

document

no

Operator to use to perform the facet over. If omitted, MongoDB Search performs the facet over all documents in the collection.

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

Important

stringFacet is now outdated. Use 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.

String facets allow you to narrow down MongoDB Search results based on the most frequent string values in the specified string field. Note that the string field must be indexed as token. To facet on string fields in embedded documents, you must also index the parent fields as the 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.

String facets have the following syntax:

{
"$searchMeta": {
"facet":{
"operator": {
<operator-specification>
},
"facets": {
"<facet-name>" : {
"type" : "string",
"path" : "<field-path>",
"numBuckets" : <number-of-categories>,
}
}
}
}
}
Option
Type
Description
Required?

numBuckets

int

Maximum number of facet categories to return in the results. Value must be less than or equal to 1000. 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 will return 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.

yes

type

string

Type of facet. Value must be string.

yes

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 type and the year field is indexed as the number type.

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

The query uses the $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.

1db.movies.aggregate([
2 {
3 "$searchMeta": {
4 "facet": {
5 "operator": {
6 "range": {
7 "path": "year",
8 "gte": 2000,
9 "lte": 2015
10 }
11 },
12 "facets": {
13 "genresFacet": {
14 "type": "string",
15 "path": "genres"
16 }
17 }
18 }
19 }
20 }
21])
1[
2 {
3 count: { lowerBound: Long('12568') },
4 facet: {
5 genresFacet: {
6 buckets: [
7 { _id: 'Drama', count: Long('7079') },
8 { _id: 'Comedy', count: Long('3689') },
9 { _id: 'Romance', count: Long('1764') },
10 { _id: 'Thriller', count: Long('1584') },
11 { _id: 'Documentary', count: Long('1472') },
12 { _id: 'Action', count: Long('1471') },
13 { _id: 'Crime', count: Long('1367') },
14 { _id: 'Adventure', count: Long('1056') },
15 { _id: 'Horror', count: Long('866') },
16 { _id: 'Biography', count: Long('796') }
17 ]
18 }
19 }
20 }
21]

To learn more about these results, see Facet Results.

Important

stringFacet is now outdated. Use 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.

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.

Numeric facets have the following syntax:

{
"$searchMeta": {
"facet":{
"operator": {
<operator-specification>
},
"facets": {
"<facet-name>" : {
"type" : "number",
"path" : "<field-path>",
"boundaries" : <array-of-numbers>,
"default": "<bucket-name>"
}
}
}
}
}
Option
Type
Description
Required?

boundaries

array of numbers

List of numeric values, in ascending order, that specify the boundaries for each bucket. You must specify at least two boundaries, which are less than or equal to one thousand ([2, 1000]). Each adjacent pair of values acts as the inclusive lower bound and the exclusive upper bound for the bucket. You can specify any combination of values of the following 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

path

string

Field path to facet on. You can specify a field that is indexed as the number type.

yes

type

string

Type of facet. Value must be number.

yes

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 type.

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

The query uses the $searchMeta stage to search the year field in the movies collection for movies between the years 1980 to 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.

1db.movies.aggregate([
2 {
3 "$searchMeta": {
4 "facet": {
5 "operator": {
6 "range": {
7 "path": "year",
8 "gte": 1980,
9 "lte": 2000
10 }
11 },
12 "facets": {
13 "yearFacet": {
14 "type": "number",
15 "path": "year",
16 "boundaries": [1980,1990,2000],
17 "default": "other"
18 }
19 }
20 }
21 }
22 }
23])
1[
2 {
3 count: { lowerBound: Long('6095') },
4 facet: {
5 yearFacet: {
6 buckets: [
7 { _id: 1980, count: Long('1956') },
8 { _id: 1990, count: Long('3558') },
9 { _id: 'other', count: Long('581') }
10 ]
11 }
12 }
13 }
14]

To learn more about these results, see Facet Results.

Important

stringFacet is now outdated. Use 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.

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.

Date facets have the following syntax:

{
"$searchMeta": {
"facet":{
"operator": {
<operator-specification>
},
"facets": {
"<facet-name>" : {
"type" : "date",
"path" : "<field-path>",
"boundaries" : <array-of-dates>,
"default": "<bucket-name>"
}
}
}
}
}
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 one thousand ([2, 1000])

  • 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

path

string

Field path to facet on. You can specify a field that is indexed as a date type.

yes

type

string

Type of facet. Value must be date.

yes

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 type.

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

The query uses the $searchMeta stage to search the released field in the movies collection for movies between the years 2000 to 2015 and retrieve metadata results for the query string. 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.

1db.movies.aggregate([
2 {
3 "$searchMeta": {
4 "facet": {
5 "operator": {
6 "range": {
7 "path": "released",
8 "gte": ISODate("2000-01-01T00:00:00.000Z"),
9 "lte": ISODate("2015-01-31T00:00:00.000Z")
10 }
11 },
12 "facets": {
13 "yearFacet": {
14 "type": "date",
15 "path": "released",
16 "boundaries": [ISODate("2000-01-01"), ISODate("2005-01-01"), ISODate("2010-01-01"), ISODate("2015-01-01")],
17 "default": "other"
18 }
19 }
20 }
21 }
22 }
23])
1[
2 {
3 count: { lowerBound: Long('11922') },
4 facet: {
5 yearFacet: {
6 buckets: [
7 {
8 _id: ISODate('2000-01-01T00:00:00.000Z'),
9 count: Long('3028')
10 },
11 {
12 _id: ISODate('2005-01-01T00:00:00.000Z'),
13 count: Long('3953')
14 },
15 {
16 _id: ISODate('2010-01-01T00:00:00.000Z'),
17 count: Long('4832')
18 },
19 { _id: 'other', count: Long('109') }
20 ]
21 }
22 }
23 }
24]

To learn more about these results, see Facet Results.

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

stringFacet (outdated)

Normalizer Support: The token type supports normalizers that transform facet buckets. For example, with normalizer: lowercase, "ADIDAS" and "adidas" count towards the same bucket while stringFacet treats them as separate buckets.

Numeric

numberFacet (outdated)

Array Support: The number type considers values within arrays for facet buckets. For example, a document with an array value [0, 10] counts towards both buckets [1, 5] and [6, 10] while numberFacet ignores array values completely.

Date

dateFacet (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.

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.

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 have their own result counts. 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.

Example

Consider a query against the sample_airbnb.listings 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 which also have a moderate cancellation_policy.

For more information, see the Multi-Select Faceting example.

Finally, for use cases with many facets, it can be useful to 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.listings 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 which 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.

When you run your query using the $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 to view the metadata results for your $search query.

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

  • $search stage for just the search results.

  • $searchMeta stage for just the metadata results.

The following limitations apply:

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

The following examples use the sample data. The metadata results example demonstrates how to run a $searchMeta query with facet to retrieve only the metadata in the results. The metadata and search results example demonstrates how to run a $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.

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

year

released

{
"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 field.

1db.movies.aggregate([
2 {
3 "$searchMeta": {
4 "facet": {
5 "operator": {
6 "range": {
7 "path": "released",
8 "gte": ISODate("2000-01-01T00:00:00.000Z"),
9 "lte": ISODate("2015-01-31T00:00:00.000Z")
10 }
11 },
12 "facets": {
13 "directorsFacet": {
14 "type": "string",
15 "path": "directors",
16 "numBuckets" : 7
17 },
18 "yearFacet" : {
19 "type" : "number",
20 "path" : "year",
21 "boundaries" : [2000,2005,2010, 2015]
22 }
23 }
24 }
25 }
26 }
27])
1[
2 {
3 count: { lowerBound: Long('11922') },
4 facet: {
5 yearFacet: {
6 buckets: [
7 { _id: 2000, count: Long('3064') },
8 { _id: 2005, count: Long('4035') },
9 { _id: 2010, count: Long('4553') }
10 ]
11 },
12 directorsFacet: {
13 buckets: [
14 { _id: 'Takashi Miike', count: Long('26') },
15 { _id: 'Johnnie To', count: Long('20') },
16 { _id: 'Steven Soderbergh', count: Long('18') },
17 { _id: 'Michael Winterbottom', count: Long('16') },
18 { _id: 'Ridley Scott', count: Long('15') },
19 { _id: 'Tyler Perry', count: Long('15') },
20 { _id: 'Clint Eastwood', count: Long('14') }
21 ]
22 }
23 }
24 }
25]

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.

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

released

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

The following query searches for movies released near July 01, 1999 using the $search stage. The query includes a $facet stage to process the input documents using the following sub-pipeline stages:

  • $project stage to exclude all fields in the documents except the title and released fields in the docs output field

  • $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 stage to include the metadata results stored in the $$SEARCH_META variable in the meta output field

The query also includes a $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.

1db.movies.aggregate([
2 {
3 "$search": {
4 "facet": {
5 "operator": {
6 "near": {
7 "path": "released",
8 "origin": ISODate("1999-07-01T00:00:00.000+00:00"),
9 "pivot": 7776000000
10 }
11 },
12 "facets": {
13 "genresFacet": {
14 "type": "string",
15 "path": "genres"
16 }
17 }
18 }
19 }
20 },
21 { "$limit": 2 },
22 {
23 "$facet": {
24 "docs": [
25 { "$project":
26 {
27 "title": 1,
28 "released": 1
29 }
30 }
31 ],
32 "meta": [
33 {"$replaceWith": "$$SEARCH_META"},
34 {"$limit": 1}
35 ]
36 }
37 },
38 {
39 "$set": {
40 "meta": {
41 "$arrayElemAt": ["$meta", 0]
42 }
43 }
44 }
45])
1[
2 {
3 docs: [
4 {
5 _id: ObjectId('573a1393f29313caabcde1ae'),
6 title: 'Begone Dull Care',
7 released: ISODate('1999-07-01T00:00:00.000Z')
8 },
9 {
10 _id: ObjectId('573a13a9f29313caabd2048a'),
11 title: 'Fara' released: ISODate('1999-07-01T00:00:00.000Z')
12 }
13 ],
14 meta: {
15 count: { lowerBound: Long('20878') },
16 facet: {
17 genresFacet: {
18 buckets: [
19 { _id: 'Drama', count: Long('12149') },
20 { _id: 'Comedy', count: Long('6436') },
21 { _id: 'Romance', count: Long('3274') },
22 { _id: 'Crime', count: Long('2429') },
23 { _id: 'Thriller', count: Long('2400') },
24 { _id: 'Action', count: Long('2349') },
25 { _id: 'Adventure', count: Long('1876') },
26 { _id: 'Documentary', count: Long('1755') },
27 { _id: 'Horror', count: Long('1432') },
28 { _id: 'Biography', count: Long('1244') }
29 ]
30 }
31 }
32 }
33 }
34]

To learn more about these results, see Facet Results.

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 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 option.

{
"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) to search for funds raised in USD .

  • Uses returnScope options to set the query context to the embeddedDocuments field named funding_rounds. To use returnScope, the query:

    • Specifies the returnStoredSource 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

1db.companies.aggregate([
2 {
3 "$searchMeta": {
4 "returnStoredSource": true,
5 "returnScope": {
6 "path": "funding_rounds"
7 },
8 "facet": {
9 "operator": {
10 "text": {
11 "path": "funding_rounds.raised_currency_code",
12 "query": "USD"
13 }
14 },
15 "facets": {
16 "raisedAmountFacet": {
17 "type": "number",
18 "path": "funding_rounds.raised_amount",
19 "boundaries": [5000000, 5250000, 5500000]
20 }
21 }
22 }
23 }
24 }
25])
1[
2 {
3 count: { lowerBound: Long('5329') },
4 facet: {
5 raisedAmountFacet: {
6 buckets: [
7 { _id: 5000000, count: Long('251') },
8 { _id: 5250000, count: Long('32') }
9 ]
10 }
11 }
12 }
13]

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

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.

{
"mappings": {
"dynamic": false,
"fields": {
"cancellation_policy": {
"type": "token"
},
"room_type": {
"type": "token"
},
"accommodates": {
"type": "number"
}
}
}
}

The following query uses the $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 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.

1db.listingsAndReviews.aggregate([
2 {
3 $searchMeta: {
4 facet: {
5 facets: {
6 accommodatesFacet: {
7 path: "accommodates",
8 type: "number",
9 boundaries: [1,2,4,8],
10 },
11 cancellationFacet: {
12 path: "cancellation_policy",
13 type: "string",
14 },
15 roomTypeFacet: {
16 path: "room_type",
17 type: "string",
18 }
19 },
20 operator: {
21 compound: {
22 must: [
23 {
24 text: {
25 path: "description",
26 query: "new york city",
27 },
28 },
29 ],
30 filter: [
31 {
32 equals: {
33 path: "cancellation_policy",
34 value: "moderate",
35 doesNotAffect:
36 "cancellationFacet",
37 },
38 },
39 ],
40 },
41 },
42 },
43 }
44 },
45]
1[
2 {
3 count: { lowerBound: Long('531') },
4 facet: {
5 accomodatesFacet: {
6 buckets: [
7 { _id: "1", count: Long('25') },
8 { _id: "2", count: Long('270') },
9 { _id: "4", count: Long('204') },
10 ]
11 },
12 cancellationFacet: {
13 buckets: [
14 { _id: "strict_14_with_grace_period", count: Long('849') },
15 { _id: "moderate", count: Long('531') },
16 { _id: "flexible", count: Long('380') },
17 { _id: "super_strict_60", count: Long('25') }
18 { _id: "super_strict_30", count: Long('380') }
19 ]
20 },
21 roomTypeFacet: {
22 buckets: [
23 { _id: "Entire home/apt", count: Long('369') },
24 { _id: "Private room", count: Long('159') },
25 { _id: "Shared room", count: Long('3') },
26 ]
27 }
28 }
29 }
30]

Observe that the counts for buckets in cancellationFacet are not reduced to zero despite the query filtering on a value of moderate.

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.

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

The following query:

  • Searches for listings that include the text new york city in their description and which have a cancellation_policy of moderate.

  • Facets on the cancellation_policy, roomType and accommodates fields.

    Each of the cancellation_policy and roomType facets have 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

  • Sets 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.

1db.listingsAndReviews.aggregate([
2 {
3 $searchMeta: {
4 facet: {
5 facets: {
6 accommodatesFacet: {
7 path: "accommodates",
8 type: "number",
9 boundaries: [1,2,4,8],
10 },
11 cancellationFacet: {
12 path: "cancellation_policy",
13 type: "string",
14 },
15 roomTypeFacet: {
16 path: "room_type",
17 type: "string",
18 }
19 },
20 operator: {
21 compound: {
22 must: [
23 {
24 text: {
25 path: "description",
26 query: "new york city",
27 },
28 },
29 ],
30 filter: [
31 {
32 equals: {
33 path: "cancellation_policy",
34 value: "moderate",
35 doesNotAffect:
36 "accommodatesFacet",
37 },
38 },
39 ],
40 },
41 },
42 },
43 },
44 },
45]
1[
2 {
3 count: { lowerBound: Long('531') },
4 facet: {
5 accomodatesFacet: {
6 buckets: [
7 { _id: "1", count: Long('25') },
8 { _id: "2", count: Long('270') },
9 { _id: "4", count: Long('204') },
10 ]
11 },
12 cancellationFacet: {
13 buckets: [
14 { _id: "flexible", count: Long('XXX') },
15 { _id: "moderate", count: Long('531') },
16 { _id: "strict_14_with_grace_period", count: Long('XXX') },
17 ]
18 },
19 roomTypeFacet: {
20 buckets: [
21 { _id: "Entire home/apt", count: Long('369') },
22 { _id: "Private room", count: Long('159') },
23 { _id: "Shared room", count: Long('3') },
24 ]
25 }
26 }
27 }
28]

To learn more, see How to Use Facets with MongoDB Search.

You can learn more about facet (MongoDB Search Operator) in MongoDB Search with our course and video.

To learn more about using facets in MongoDB Search, take Unit 9 of the Intro To MongoDB Course on MongoDB University. The 1.5 hour unit includes an overview of MongoDB Search and lessons on creating MongoDB Search indexes, running $search queries using compound operators, and grouping results using facet.

Follow along with this video to learn about how you can create and use a numeric and string facet (MongoDB Search Operator) in your query to group results and retrieve a count of the results in the groups.

Duration: 11 Minutes