Definition
facetThe
facetcollector groups results by values or ranges in the specified faceted fields and returns the count for each of those groups.You can use
facetwith both the$searchand$searchMetastages. MongoDB recommends usingfacetwith the$searchMetastage to retrieve metadata results only for the query. To retrieve metadata results and query results using the$searchstage, you must use the$$SEARCH_METAaggregation variable. To learn more, seeSEARCH_METAAggregation Variable.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:
Nested fields inside an array of objects, see returnScope Example.
Root
embeddedDocumentstype field, see Facet Query.
Syntax
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 } }
Fields
Field | Type | Required? | Description |
|---|---|---|---|
| document | yes | Information for bucketing the data for each facet. You must specify at least one Facet Definition. Each facet definition can also specify Facet Aggregations to compute metrics for each bucket. |
| document | no | Operator 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 or nested facets 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. To get sizing guidance for your workload, request 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, 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.
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
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. 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.
Syntax
String facets have the following syntax:
{ "$searchMeta": { "facet":{ "operator": { <operator-specification> }, "facets": { "<facet-name>" : { "type" : "string", "path" : "<field-path>", "numBuckets" : <number-of-categories>, } } } } }
Options
Option | Type | Description | Required? |
|---|---|---|---|
| int | Maximum number of facet categories to return in the results. Value must be less than or equal to | no |
| string | Field path to facet on. You can specify a field that is indexed as a token. | yes |
| string | Type of facet. Value must be | 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 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.
1 db.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 ])
To learn more about these results, see Facet Results.
Numeric Facets
Important
numberFacet is now outdated. Use 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.
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:
{ "$searchMeta": { "facet":{ "operator": { <operator-specification> }, "facets": { "<facet-name>" : { "type" : "number", "path" : "<field-path>", "boundaries" : <array-of-numbers>, "default": "<bucket-name>" } } } } }
Options
Option | Type | Description | Required? |
|---|---|---|---|
| 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 (
| yes |
| 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 |
| string | Field path to facet on. You can specify a field that is indexed as the number type. | yes |
| string | Type of facet. Value must be | 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 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 and 2000 and retrieve metadata results for the query. The query specifies three buckets:
1980, inclusive lower bound for this bucket1990, exclusive upper bound for the1980bucket and inclusive lower bound for this bucket2000, exclusive upper bound for the1990bucket
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.
1 db.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 ])
To learn more about these results, see Facet Results.
Date Facets
Important
dateFacet is now outdated. Use 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.
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:
{ "$searchMeta": { "facet":{ "operator": { <operator-specification> }, "facets": { "<facet-name>" : { "type" : "date", "path" : "<field-path>", "boundaries" : <array-of-dates>, "default": "<bucket-name>" } } } } }
Options
Option | Type | Description | Required? |
|---|---|---|---|
| array of numbers | List of date values that specify the boundaries for each bucket. You must specify:
Each adjacent pair of values acts as the inclusive lower bound and the exclusive upper bound for the bucket. | yes |
| 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 |
| string | Field path to facet on. You can specify a field that is indexed as a date type. | yes |
| string | Type of facet. Value must be | 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 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 and 2015 and retrieve metadata results for the query. The query specifies four buckets:
2000-01-01, inclusive lower bound for this bucket2005-01-01, exclusive upper bound for the2000-01-01bucket and inclusive lower bound for this bucket2010-01-01, exclusive upper bound for the2005-01-01bucket and inclusive lower bound for this bucket2015-01-01, exclusive upper bound for the2010-01-01bucket
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.
1 db.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 ])
To learn more about these results, see 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 | stringFacet (outdated) | Normalizer Support: The | |
Numeric | numberFacet (outdated) | Array Support: The | |
Date | dateFacet (outdated) | Array Support: The |
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 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.
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 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
pathfor each metric astoken,number, ordate.Explicitly include the
countmetric if you want the bucket count.Only specify
aggregationsat 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
aggregationsand no nested facet.
MongoDB Search computes aggregations over the data in the MongoDB Search index, which is eventually consistent.
Note
Memory Requirements
Facet queries that specify aggregations or nested facets increase the memory and disk that your MongoDB Search index requires beyond the requirements for other facet queries. To learn more, see Memory Requirements.
Syntax
aggregations has the following syntax:
{ "$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? |
|---|---|---|---|
| string | Field path to compute the metric over. This is required for all metric types except | conditional |
| string | Type of metric to compute. Value can be one of the following:
To learn more about each metric type, see Metric Types. | yes |
Metric Types
Type | Field Requirements | Description |
|---|---|---|
| None | Counts the documents in the bucket. Don't specify a |
| Adds the values of the specified field for the documents in the bucket. | |
| 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 | |
| None | Returns the lowest value of the specified field for the documents in the bucket. |
| None | Returns the highest value of the specified field for the documents in the bucket. |
| None | Returns the value of the specified field for the first document in the bucket, according to the order that the query sort 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. |
| None | Returns the value of the specified field for the last document in the bucket, according to the order that the query sort 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. |
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 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:
sumandavgskip the document.minandmaxselect the lowest and highest value in the array to use as a representative element for the document.firstandlastreturn 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 for the field in your index definition and set returnStoredSource 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.
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. You can nest facets without limit on the number of levels. However, the following restrictions apply:
You can specify
aggregationsonly on a leaf facet in a nested facet tree. A facet definition that specifiesfacetscan't also specifyaggregations. To compute metrics for an intermediate grouping, specify that grouping as a separate top-level facet withaggregationsand no nested facet.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 isnumBucketsfor a string facet or the number of buckets thatboundariesanddefaultdefine for a number or date facet. For example, a facet that requests20buckets and contains a nested facet that requests20buckets produces400unique 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 |
|---|---|---|
| object | Unique identifier that identifies this facet bucket. This value matches the type of data that is being faceted on. |
| int | Count of documents in this facet bucket. To learn more about the |
If the facet definition specifies Facet Aggregations, 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, each bucket document contains a facet field with 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_policyroom_typeaccommodates
The cancellation_policy facet has the following buckets:
flexiblemoderatestrict_14_with_grace_periodsuper_strict_30super_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:
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. To learn more, see 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.
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.
SEARCH_META Aggregation Variable
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. You can also use the $$SEARCH_META variable with facet.aggregations.
MongoDB recommends using the $$SEARCH_META variable only if you need both the search results and the metadata results. Otherwise, use the:
$searchstage for just the search results.$searchMetastage for just the metadata results.
Limitations
The following limitations apply to Facet Aggregations:
You can't use the following options with
aggregations:doesNotAffectfor Multi-Select Facets
You can't facet or compute aggregations on the following BSON types:
binDatabooldecimalnullobjectIdtimestamp
To compute metrics over one of these types, use a view to convert the field to a supported type before you index it.
Examples
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. The nested facet example demonstrates how to group results by a second field and compute metrics for each bucket.
The index definition on the sample_mflix.movies collection specifies the following for the fields to index:
{ "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.
1 db.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 ])
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.
The index definition on the sample_mflix.movies collection specifies the following for the fields to index:
{ "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:
$projectstage to exclude all fields in the documents except thetitleandreleasedfields in thedocsoutput field$limitstage to do the following:Limit the
$searchstage output to2documentsLimit the output to
1document in themetaoutput field
Note
The limit must be small for the results to fit in a 16 MB document.
$replaceWithstage to include the metadata results stored in the$$SEARCH_METAvariable in themetaoutput 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.
1 db.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 ])
To learn more about these results, see Facet Results.
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 inUSD.Uses returnScope options to set the query context to the
embeddedDocumentsfield namedfunding_rounds. To usereturnScope, the query:- Specifies the returnStoredSource option, which is required, to return the stored source fields.
Facets on the
raised_amountfield in thefunding_roundsarray 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
1 db.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 ])
In the preceding MongoDB Search results, the facet counts are based on the embedded child documents and not the parents.
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": true, "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, andaccommodatesfields.The
cancellation_policyfacet has the following buckets:"strict_14_with_grace_period""moderate""flexible""super_strict_30""super_strict_60"
The
room_typefacet has the following buckets:"Entire home/apt""Private room""Shared room"
The query breaks the
accommodatesfacet into buckets for:1, inclusive lower bound for this bucket2, exclusive upper bound for the1bucket and inclusive lower bound for this bucket.4, exclusive upper bound for the2bucket and inclusive lower bound for this bucket.8, exclusive upper bound for the4bucket
Perform a
compoundOperator search for listings that must contain the textnew york cityin thedescriptionand filters the results for listings with amoderatecancellation_policy. ThedoesNotAffectsetting ensures that filtering by amoderatecancellation_policydoesn'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.
1 db.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 ]
The counts for buckets in cancellationFacet are not reduced to zero even though the query filters on a value of moderate.
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:
Search for listings that include the text
new york cityin theirdescriptionand that have acancellation_policyofmoderate.Facet on the
cancellation_policy,roomType, andaccommodatesfields.Each of the
cancellation_policyandroomTypefacets has three buckets, corresponding to the three unique values of these fields across the collection. The query breaks theaccommodatesfacet into buckets for:1, inclusive lower bound for this bucket2, exclusive upper bound for the1bucket and inclusive lower bound for this bucket.4, exclusive upper bound for the2bucket and inclusive lower bound for this bucket.8, exclusive upper bound for the4bucket
Set the
doesNotAffectproperty in theequalsoperator of thecompound.filtertoaccommodatesFacet. This excludes the buckets within theaccommodatesfacet from filtering. As a result, filtering on themoderatecancellation_policyreduces the counts of other buckets in thecancellation_policyfacet to0, and reduces the counts of buckets in theroomTypefacet, but the counts of buckets in theaccommodatesfacet are unchanged. This allows you to compare the impact of filtering on different facets.
1 db.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 ]
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 type and the accommodates field is indexed as the number type.
{ "mappings": { "dynamic": false, "fields": { "property_type": [ { "type": "token" } ], "amenities": [ { "type": "token" } ], "accommodates": [ { "type": "number" } ] } } }
The query uses the $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.
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" } } } } } } } ])
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 type and the bedrooms and accommodates fields are indexed as the number type.
{ "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. The query computes the number of listings and the largest number of guests that a listing accommodates for each bedroom range.
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" } } } } } } } } } ])
Continue Learning
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.
Learn with Courses
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.
Learn by Watching
Watch 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