Database Manual / Reference / Query Language / Aggregation Stages

$facet (aggregation stage)(聚合阶段)

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. $facet阶段允许您创建多面聚合,在单个聚合阶段内跨多个维度或方面表征数据。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.输入文档只传递到$facet阶段一次。$facet允许对同一组输入文档进行各种聚合,而无需多次检索输入文档。

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阶段具有以下形式:

{ $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.$facet中的每个阶段执行时,生成的文档被限制为100兆字节。请注意,allowDiskUse标志不会影响100兆字节的大小限制,因为$facet不会溢出到磁盘。

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 sub-pipeline's <stage> to perform a multi-faceted aggregation:与Facet相关的聚合阶段对传入文档进行分类和分组。在不同的$facet子管道的<stage>中指定以下任何与方面相关的阶段,以执行多面聚合:

Other aggregation stages can also be used with $facet with the following exceptions:除了以下例外情况,其他聚合阶段也可以与$facet一起使用:

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 $facet stage is the first stage in a pipeline, the stage will perform a COLLSCAN. The $facet stage does not make use of indexes if it is the first stage in the pipeline.如果$facet阶段是管道中的第一阶段,则该阶段将执行COLLSCAN。如果$facet阶段是管道中的第一个阶段,则它不使用索引。
  • If the $facet stage comes later in the pipeline and earlier stages have used indexes, $facet will not trigger a COLLSCAN during execution.如果$facet阶段在管道的后期出现,并且早期阶段已经使用了索引,则$facet在执行过程中不会触发COLLSCAN

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.例如,在$facet阶段之前的$match$sort阶段可以使用索引,而$facet不会触发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. 以下操作使用MongoDB的分面功能为客户提供跨多个维度(如标签、价格和创建年份)分类的商店inventoryThis $facet stage has three sub-pipelines that use $sortByCount, $bucket, or $bucketAuto to perform this multi-faceted aggregation. 这个$facet阶段有三个子管道,它们使用$sortByCount$bucket$bucketAuto来执行这种多面聚合。The input documents from artwork are fetched from the database only once, at the beginning of the operation:在操作开始时,artwork(艺术品)的输入文档只从数据库中提取一次:

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.本页上的C#示例使用Atlas示例数据集中sample_mflix数据库。要了解如何创建免费的MongoDB Atlas集群并加载示例数据集,请参阅MongoDB NET/C#驱动程序文档中的入门

The following Movie class models the documents in the sample_mflix.movies collection:以下Movie类对sample_mflix.movies集合中的文档进行建模:

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; }

[BsonElement("lastupdated")]
public DateTime LastUpdated { get; set; }
}

Note

ConventionPack for Pascal CasePascal大小写的约定包

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:此页面上的C#类使用Pascal大小写作为其属性名,但MongoDB集合中的字段名使用驼峰大小写。为了解释这种差异,您可以在应用程序启动时使用以下代码注册ConventionPack

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.要使用MongoDB NET/C#驱动程序向聚合管道添加$facet阶段,请在PipelineDefinition对象上调用Facet()方法。

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.第一个聚合根据其Runtime字段的值将传入文档分为五组。第二个聚合对Rated字段中的每个值进行计数,并返回每个值的计数,仅限于前五个值。

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. 本页上的Node.js示例使用Atlas示例数据集中的sample_mflix数据库。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.要了解如何创建免费的MongoDB Atlas集群并加载示例数据集,请参阅MongoDB Node.js驱动程序文档中的入门

To use the MongoDB Node.js driver to add a $facet stage to an aggregation pipeline, use the $facet operator in a pipeline object.要使用MongoDB Node.js驱动程序向聚合管道添加$facet阶段,请在管道对象中使用$facet运算符。

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. 以下示例创建了一个执行两个并行聚合的管道阶段。第一个聚合使用$bucketAuto阶段,根据runtime字段的值将传入文档分为五组。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:第二个聚合对rated(额定)字段中的每个值进行计数,并使用$sortByCount$limit阶段返回前五个值的计数。然后,该示例运行聚合管道:

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.要了解有关相关管道阶段的更多信息,请参阅$bucketAuto$sortByCount$limit指南。