Definition定义
$facetProcesses 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
$facetstage 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
$facetstage only once.$facetenables various aggregations on the same set of input documents, without needing to retrieve the input documents multiple times.
Compatibility兼容性
You can use 您可以将$facet for deployments hosted in the following environments:$facet用于在以下环境中托管的部署:
- MongoDB Atlas
: The fully managed service for MongoDB deployments in the cloud:云中MongoDB部署的完全托管服务
- MongoDB Enterprise
: The subscription-based, self-managed version of MongoDB:MongoDB的基于订阅的自我管理版本 - MongoDB Community
: The source-available, free-to-use, and self-managed version of MongoDB:MongoDB的源代码可用、免费使用和自我管理版本
Syntax语法
The $facet stage has the following form:
{ $facet:
{
<outputField1>: [ <stage1>, <stage2>, ... ],
<outputField2>: [ <stage1>, <stage2>, ... ],
...
}
}
Specify the output field name for each specified pipeline.
Considerations
As each stage in a $facet executes, the resulting document is limited to 100 megabytes. Note the allowDiskUse flag doesn't affect the 100 megabyte size limit, since $facet can't spill to disk.
The final output document is subject to the 16 mebibyte BSON document size limit. If it exceeds 16 mebibytes, the aggregation produces an error.最终输出文档受16兆字节BSON文档大小限制。如果超过16兆字节,聚合将产生错误。
Behavior行为
Facet-related aggregation stages categorize and group incoming documents. Specify any of the following facet-related stages within different 与Facet相关的聚合阶段对传入文档进行分类和分组。在不同的$facet sub-pipeline's <stage> to perform a multi-faceted aggregation:$facet子管道的<stage>中指定以下任何与方面相关的阶段,以执行多面聚合:
Other aggregation stages can also be used with 除了以下例外情况,其他聚合阶段也可以与$facet with the following exceptions:$facet一起使用:
$collStats$facet$geoNear$indexStats$out$merge$planCacheStats$search$searchMeta$vectorSearch
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. $facet中的每个子管道都传递一组完全相同的输入文档。这些子管道彼此完全独立,每个子管道输出的文档数组存储在输出文档中的单独字段中。The output of one sub-pipeline can not be used as the input for a different sub-pipeline within the same 一个子管道的输出不能用作同一$facet stage. $facet阶段内不同子管道的输入。If further aggregations are required, add additional stages after 如果需要进一步聚合,请在$facet and specify the field name, <outputField>, of the desired sub-pipeline output.$facet之后添加其他阶段,并指定所需子管道输出的字段名<outputField>。
Index Use索引使用
Pipeline order determines how the 管道顺序决定了$facet stage uses indexes.$facet阶段如何使用索引。
- If the
$facetstage is the first stage in a pipeline, the stage will perform aCOLLSCAN. The$facetstage does not make use of indexes if it is the first stage in the pipeline. - If the
$facetstage comes later in the pipeline and earlier stages have used indexes,$facetwill not trigger aCOLLSCANduring 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.
Examples示例
MongoDB Shell
Consider an online store whose inventory is stored in the following 考虑一个在线商店,其artwork collection:inventory存储在以下artwork(艺术品)集合中:
{ "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926,
"price" : Decimal128("199.99"),
"tags" : [ "painting", "satire", "Expressionism", "caricature" ] }
{ "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902,
"price" : Decimal128("280.00"),
"tags" : [ "woodcut", "Expressionism" ] }
{ "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925,
"price" : Decimal128("76.04"),
"tags" : [ "oil", "Surrealism", "painting" ] }
{ "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai",
"price" : Decimal128("167.30"),
"tags" : [ "woodblock", "ukiyo-e" ] }
{ "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,
"price" : Decimal128("483.00"),
"tags" : [ "Surrealism", "painting", "oil" ] }
{ "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,
"price" : Decimal128("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" : Decimal128("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 }
]
}C#
The C# examples on this page use the sample_mflix database from the Atlas sample datasets. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see Get Started in the MongoDB .NET/C# Driver documentation.
The following Movie class models the documents in the sample_mflix.movies collection:
public class Movie
{
public ObjectId Id { get; set; }
public int Runtime { get; set; }
public string Title { get; set; }
public string Rated { get; set; }
public List<string> Genres { get; set; }
public string Plot { get; set; }
public ImdbData Imdb { get; set; }
public int Year { get; set; }
public int Index { get; set; }
public string[] Comments { get; set; }
[]
public DateTime LastUpdated { get; set; }
}
Note
ConventionPack for Pascal Case
The C# classes on this page use Pascal case for their property names, but the field names in the MongoDB collection use camel case. To account for this difference, you can use the following code to register a ConventionPack when your application starts:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);To use the MongoDB .NET/C# driver to add a $facet stage to an aggregation pipeline, call the Facet() method on a PipelineDefinition object.
The following example creates a pipeline stage that executes two parallel aggregations. The first aggregation distributes incoming documents into five groups by the value of their Runtime field. The second aggregation counts each value in the Rated field and returns the count for each value, limited to the top five values.
var bucketPipeline = new EmptyPipelineDefinition<Movie>()
.BucketAuto(
groupBy: m => m.Runtime,
buckets: 5);
var bucketFacet = AggregateFacet.Create(
name: "Runtimes",
pipeline: bucketPipeline);
var countLimitPipeline = new EmptyPipelineDefinition<Movie>()
.SortByCount(m => m.Rated)
.Limit(5);
var countFacet = AggregateFacet.Create(
"Ratings", countLimitPipeline);
var pipeline = new EmptyPipelineDefinition<Movie>()
.Facet(bucketFacet, countFacet);Node.js
The Node.js examples on this page use the sample_mflix database from the Atlas sample datasets. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see Get Started in the MongoDB Node.js driver documentation.
To use the MongoDB Node.js driver to add a $facet stage to an aggregation pipeline, use the $facet operator in a pipeline object.
The following example creates a pipeline stage that executes two parallel aggregations. The first aggregation distributes incoming documents into five groups by the value of their runtime field by using the $bucketAuto stage. The second aggregation counts each value in the rated field and returns the count of the top five values by using the $sortByCount and $limit stages. The example then runs the aggregation pipeline:
const pipeline = [
{
$facet: {
bucketPipeline: [
{
$bucketAuto: {
groupBy: "$runtime",
buckets: 5
}
}
],
countLimit: [
{ $sortByCount: "$rated" },
{ $limit: 5 }
]
}
}
];
const cursor = collection.aggregate(pipeline);
return cursor;Learn More了解更多
To learn more about related pipeline stages, see the $bucketAuto, $sortByCount, and $limit guides.