$facet (aggregation)
On this page
Definition
$facet
Processes multiple aggregation pipelines within a single stage on the same set of input documents. Each sub-pipeline has its own field in the output document where its results are stored as an array of documents.
The
$facet
stage allows you to create multi-faceted aggregations which characterize data across multiple dimensions, or facets, within a single aggregation stage. Multi-faceted aggregations provide multiple filters and categorizations to guide data browsing and analysis. Retailers commonly use faceting to narrow search results by creating filters on product price, manufacturer, size, etc.Input documents are passed to the
$facet
stage only once.$facet
enables various aggregations on the same set of input documents, without needing to retrieve the input documents multiple times.The
$facet
stage has the following form:{ $facet: { <outputField1>: [ <stage1>, <stage2>, ... ], <outputField2>: [ <stage1>, <stage2>, ... ], ... } } Specify the output field name for each specified pipeline.
Considerations
The output of the $facet
stage is subject to the 16 megabyte
BSON Document Size limit. If the results
of the $facet
stage exceed the BSON Document Size
limit, the aggregation produces an error.
Behavior
Facet-related aggregation stages categorize and group incoming
documents. Specify any of the following facet-related stages within
different $facet
sub-pipeline's <stage>
to perform a
multi-faceted aggregation:
Other
aggregation stages can
also be used with $facet
with the following exceptions:
Each sub-pipeline within $facet
is passed the exact same set of
input documents. These sub-pipelines are completely independent of one
another and the document array output by each is stored in separate
fields in the output document. The output of one sub-pipeline can not
be used as the input for a different sub-pipeline within the same
$facet
stage. If further aggregations are required, add additional
stages after $facet
and specify the field name, <outputField>
,
of the desired sub-pipeline output.
Index Use
Pipeline order determines how the $facet
stage uses indexes.
If the
$facet
stage is the first stage in a pipeline, the stage will perform aCOLLSCAN
. The$facet
stage does not make use of indexes if it is the first stage in the pipeline.If the
$facet
stage comes later in the pipeline and earlier stages have used indexes,$facet
will not trigger aCOLLSCAN
during execution.
For example, $match
or $sort
stages that come
before a $facet
stage can make use of indexes and the $facet
will not trigger a COLLSCAN
.
For optimization suggestions, see: Aggregation Pipeline Optimization.
Example
Consider an online store whose inventory is stored in the following
artwork
collection:
{ "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926, "price" : NumberDecimal("199.99"), "tags" : [ "painting", "satire", "Expressionism", "caricature" ] } { "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902, "price" : NumberDecimal("280.00"), "tags" : [ "woodcut", "Expressionism" ] } { "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925, "price" : NumberDecimal("76.04"), "tags" : [ "oil", "Surrealism", "painting" ] } { "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai", "price" : NumberDecimal("167.30"), "tags" : [ "woodblock", "ukiyo-e" ] } { "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931, "price" : NumberDecimal("483.00"), "tags" : [ "Surrealism", "painting", "oil" ] } { "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913, "price" : NumberDecimal("385.00"), "tags" : [ "oil", "painting", "abstract" ] } { "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893, "tags" : [ "Expressionism", "painting", "oil" ] } { "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918, "price" : NumberDecimal("118.42"), "tags" : [ "abstract", "painting" ] }
The following operation uses MongoDB's faceting features to provide
customers with the store's inventory categorized across multiple
dimensions such as tags, price, and year created. This
$facet
stage has three sub-pipelines that use
$sortByCount
, $bucket
, or
$bucketAuto
to perform this multi-faceted aggregation.
The input documents from artwork
are fetched from the database only
once, at the beginning of the operation:
db.artwork.aggregate( [ { $facet: { "categorizedByTags": [ { $unwind: "$tags" }, { $sortByCount: "$tags" } ], "categorizedByPrice": [ // Filter out documents without a price e.g., _id: 7 { $match: { price: { $exists: 1 } } }, { $bucket: { groupBy: "$price", boundaries: [ 0, 150, 200, 300, 400 ], default: "Other", output: { "count": { $sum: 1 }, "titles": { $push: "$title" } } } } ], "categorizedByYears(Auto)": [ { $bucketAuto: { groupBy: "$year", buckets: 4 } } ] } } ])
The operation returns the following document:
{ "categorizedByYears(Auto)" : [ // First bucket includes the document without a year, e.g., _id: 4 { "_id" : { "min" : null, "max" : 1902 }, "count" : 2 }, { "_id" : { "min" : 1902, "max" : 1918 }, "count" : 2 }, { "_id" : { "min" : 1918, "max" : 1926 }, "count" : 2 }, { "_id" : { "min" : 1926, "max" : 1931 }, "count" : 2 } ], "categorizedByPrice" : [ { "_id" : 0, "count" : 2, "titles" : [ "Dancer", "Blue Flower" ] }, { "_id" : 150, "count" : 2, "titles" : [ "The Pillars of Society", "The Great Wave off Kanagawa" ] }, { "_id" : 200, "count" : 1, "titles" : [ "Melancholy III" ] }, { "_id" : 300, "count" : 1, "titles" : [ "Composition VII" ] }, { // Includes document price outside of bucket boundaries, e.g., _id: 5 "_id" : "Other", "count" : 1, "titles" : [ "The Persistence of Memory" ] } ], "categorizedByTags" : [ { "_id" : "painting", "count" : 6 }, { "_id" : "oil", "count" : 4 }, { "_id" : "Expressionism", "count" : 3 }, { "_id" : "Surrealism", "count" : 2 }, { "_id" : "abstract", "count" : 2 }, { "_id" : "woodblock", "count" : 1 }, { "_id" : "woodcut", "count" : 1 }, { "_id" : "ukiyo-e", "count" : 1 }, { "_id" : "satire", "count" : 1 }, { "_id" : "caricature", "count" : 1 } ] }