facet
On this page
Compatibility
facet
is only available on Atlas clusters running one of the
following versions:
MongoDB 5.0.4+
MongoDB 6.0+
MongoDB 7.0+
Note
To run facet queries over sharded collections, your cluster must run MongoDB v6.0 or higher.
You can't run facet
queries with explain.
Definition
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 usingfacet
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. SeeSEARCH_META
Aggregation Variable to learn more.
Syntax
facet
has the following syntax:
{ "$searchMeta"|"$search": { "index": <index name>, // optional, defaults to "default" "facet": { "operator": { <operator-specifications> }, "facets": { <facet-definitions> } } } }
Fields
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, Atlas Search performs the facet over all documents in
the collection. |
Facet Definition
The facet definition document contains the facet name and options specific to a type of facet. Atlas Search supports the following types of facets:
String Facets
String facets allow you to narrow down Atlas Search results based on the most frequent string values in the specified string field. Note that the string field must be indexed as stringFacet. To facet on string fields in embedded documents, you must also index the parent fields as the document type.
Note
When you facet on a string field inside embedded documents, Atlas Search returns facet count for only the number of matching parent 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? |
---|---|---|---|
numBuckets | int | Maximum number of facet categories to return in the results.
Value must be less than or equal to 1000 . If specified,
Atlas 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 Atlas 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 stringFacet. | 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 stringFacet type and the year
field is
indexed as the number type.
{ "mappings": { "dynamic": false, "fields": { "genres": { "type": "stringFacet" }, "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.
db.movies.aggregate([ { "$searchMeta": { "facet": { "operator": { "range": { "path": "year", "gte": 2000, "lte": 2015 } }, "facets": { "genresFacet": { "type": "string", "path": "genres" } } } } } ])
This query returns the following results:
[ { count: { lowerBound: Long("13718") }, facet: { genresFacet: { buckets: [ { _id: 'Drama', count: Long("7759") }, { _id: 'Comedy', count: Long("3937") }, { _id: 'Romance', count: Long("1916") }, { _id: 'Thriller', count: Long("1705") }, { _id: 'Documentary', count: Long("1703") }, { _id: 'Action', count: Long("1558") }, { _id: 'Crime', count: Long("1475") }, { _id: 'Adventure', count: Long("1111") }, { _id: 'Horror', count: Long("1008") }, { _id: 'Biography', count: Long("877") } ] } } } ]
To learn more about these results, see Facet Results.
Numeric Facets
Numeric facets allow you to determine the frequency of numeric values in your search results by breaking the results into separate ranges of numbers.
Note
Limitation
You can't facet on numeric fields in embedded 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? |
---|---|---|---|
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. 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:
| 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, Atlas 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 numberFacet
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 numberFacet and number types.
{ "mappings": { "dynamic": false, "fields": { "year": [ { "type": "numberFacet" }, { "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 bucket1990
, exclusive upper bound for the1980
bucket and inclusive lower bound for this bucket2000
, exclusive upper bound for the1990
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.
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" } } } } } ])
This query returns the following results:
[ { 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.
Date Facets
Date facets allow you to narrow down search results based on a date.
Note
Limitation
You can't facet on date fields in embedded 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? |
---|---|---|---|
boundaries | 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 |
default | string | Name of an additional bucket that counts documents returned from
the operator that do not fall within the specified boundaries.
If omitted, Atlas Search includes the results of the facet operator
that do not fall under a specified bucket also, but Atlas 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 dateFacet 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 dateFacet and date
types.
{ "mappings": { "dynamic": false, "fields": { "released": [ { "type": "dateFacet" }, { "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 bucket2005-01-01
, exclusive upper bound for the2000-01-01
bucket and inclusive lower bound for this bucket2010-01-01
, exclusive upper bound for the2005-01-01
bucket and inclusive lower bound for this bucket2015-01-01
, exclusive upper bound for the2010-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.
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" } } } } } ])
This query returns the following results:
[ { 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.
Facet Results
For a facet query, Atlas 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 Atlas Search Results. |
SEARCH_META
Aggregation Variable
When you run your query using the $search
stage, Atlas 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.
Limitations
The following limitations apply:
You can run facet queries on a single field only. You can't run facet queries on groups of fields.
You can run facet queries over sharded collections on clusters running MongoDB v6.0 only.
Examples
The following examples use the sample_mflix.movies
collection. 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 index definition specifies the following for the fields to index:
Field Name | Data Type |
---|---|
directors | |
year | |
released |
{ "mappings": { "dynamic": false, "fields": { "directors": { "type": "stringFacet" }, "year": { "type": "numberFacet" }, "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.
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] } } } } } ])
Atlas Search returns the following results:
[ { "count" : { "lowerBound" : NumberLong(13064) }, "facet" : { "yearFacet" : { "buckets" : [ { "_id" : 2000, "count" : NumberLong(3283) }, { "_id" : 2005, "count" : NumberLong(4365) }, { "_id" : 2010, "count" : NumberLong(5123) } ] }, "directorsFacet" : { "buckets" : [ { "_id" : "Takashi Miike", "count" : NumberLong(29) }, { "_id" : "Johnnie To", "count" : NumberLong(23) }, { "_id" : "Steven Soderbergh", "count" : NumberLong(21) }, { "_id" : "Michael Winterbottom", "count" : NumberLong(19) }, { "_id" : "Ken Loach", "count" : NumberLong(16) }, { "_id" : "Ki-duk Kim", "count" : NumberLong(16) }, { "_id" : "Ridley Scott", "count" : NumberLong(15) } ] } } } ]
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 Atlas Search returned for the query
Number of movies for each director that Atlas Search returned for the query
The index definition specifies the following for the fields to index:
Field Name | Data Type |
---|---|
genres | |
released |
{ "mappings": { "dynamic": false, "fields": { "genres": { "type": "stringFacet" }, "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 thetitle
andreleased
fields in thedocs
output field$limit
stage to do the following:Limit the
$search
stage output to2
documentsLimit the output to
1
document in themeta
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 themeta
output field
The query also includes a $set
stage to add the
meta
field.
Note
To see the metadata results for the following query, Atlas Search must return documents that match the query.
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] } } } ])
The query returns the following results:
[ { 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.