$unionWith (aggregation)

On this page本页内容

Definition定义

$unionWith

New in version 4.4.版本4.4中的新功能。

Performs a union of two collections; i.e. $unionWith combines pipeline results from two collections into a single result set. 执行两个集合的并集;亦即$unionWith将来自两个集合的管道结果合并到一个结果集中。The stage outputs the combined result set (including duplicates) to the next stage.该阶段将组合结果集(包括副本)输出到下一阶段。

Syntax语法

The $unionWith stage has the following syntax:$unionWith阶段语法如下所示:

{ $unionWith: { coll: "<collection>", pipeline: [ <stage1>, ... ] } }

To include all documents from the specified collection without any processing, you can use the simplified form:要在不进行任何处理的情况下包含指定集合中的所有文档,可以使用简化形式:

{ $unionWith: "<collection>" }  // Include all documents from the specified collection

The $unionWith stage takes a document with the following fields:$unionWith阶段接收包含以下字段的文档:

Field字段Description描述
coll

The collection or view whose pipeline results you wish to include in the result set.要在结果集中包含其管道结果的集合或视图。

pipeline

Optional. 可选。An aggregation pipeline to apply to the specified coll.要应用于指定coll的聚合管道。

[ <stage1>, <stage2>, ...]

The pipeline cannot include the $out and $merge stages.管道不能包括$out$merge阶段。

The $unionWith operation would correspond to the following SQL statement:$unionWith操作将对应于以下SQL语句:

SELECT *
FROM Collection1
WHERE ...
UNION ALL
SELECT *
FROM Collection2
WHERE ...

Considerations考虑事项

Duplicates Results复制结果

The combined results from the previous stage and the $unionWith stage can include duplicates.前一阶段和$unionWith阶段的合并结果可以包含重复结果。

For example, create a suppliers collection:例如,创建供应商集合:

db.suppliers.insertMany([
  { _id: 1, supplier: "Aardvark and Sons", state: "Texas" },
  { _id: 2, supplier: "Bears Run Amok.", state: "Colorado"},
  { _id: 3, supplier: "Squid Mark Inc. ", state: "Rhode Island" },
])
db.warehouses.insertMany([
  { _id: 1, warehouse: "A", region: "West", state: "California" },
  { _id: 2, warehouse: "B", region: "Central", state: "Colorado"},
  { _id: 3, warehouse: "C", region: "East", state: "Florida" },
])

The following aggregation which combines the results from the state field projection from the suppliers collection with the results from the state field projection from the warehouse collection:以下聚合将来自suppliers集合的state字段投影的结果与来自warehouse集合的state字段投影的结果相结合:

db.suppliers.aggregate([
   { $project: { state: 1, _id: 0 } },
   { $unionWith: { coll: "warehouses", pipeline: [ { $project: { state: 1, _id: 0 } } ]} }
])

As can be seen from the returned documents, the result set contains duplicates:从返回的文档中可以看出,结果集包含重复项:

{ "state" : "Texas" }
{ "state" : "Colorado" }{ "state" : "Rhode Island" }
{ "state" : "California" }
{ "state" : "Colorado" }{ "state" : "Florida" }

To remove the duplicates, you can include a $group stage to group by the state field:要删除重复项,可以在包含$group阶段以按state字段分组:

db.suppliers.aggregate([
   { $project: { state: 1, _id: 0 } },
   { $unionWith: { coll: "warehouses", pipeline: [ { $project: { state: 1, _id: 0 } } ]} },
   { $group: { _id: "$state" } }
])

The result set no longer contains duplicates:结果集不再包含重复项:

{ "_id" : "California" }
{ "_id" : "Texas" }
{ "_id" : "Florida" }
{ "_id" : "Colorado" }
{ "_id" : "Rhode Island" }

$unionWith a Sharded Collection碎片集合

If the $unionWith stage is part of the $lookup pipeline, the $unionWith coll cannot be sharded. 如果$unionWith阶段是$lookup管道的一部分,则$unionWithcoll不能被分片。For example, in the following aggregation operation, the inventory_q1 collection cannot be sharded:例如,在以下聚合操作中,inventory_q1集合不能分片:

db.suppliers.aggregate([
   {
      $lookup: {
         from: "warehouses",
         let: { order_item: "$item", order_qty: "$ordered" },
         pipeline: [
            ...
{ $unionWith: { coll: "inventory_q1", pipeline: [ ... ] } },            ...
         ],
         as: "stockdata"
      }
   }
])

Collation排序规则

If the db.collection.aggregate() includes a collation, that collation is used for the operation, ignoring any other collations.如果db.collection.aggregate()包含排序规则,则该排序规则用于操作,忽略任何其他排序规则。

If the db.collection.aggregate() does not include a collation, the db.collection.aggregate() method uses the collation for the top-level collection/view on which the db.collection.aggregate() is run:如果db.collection.aggregate()不包含排序规则,db.collection.aggregate()方法将使用运行db.collection.aggregate()的顶级集合/视图的排序规则

  • If the $unionWith coll is a collection, its collation is ignored.如果$unionWith coll是一个集合,则忽略其排序规则。
  • If the $unionWith coll is a view, then its collation must match that of the top-level collection/view. 如果$unionWith coll是一个视图,那么它的排序规则必须与顶级集合/视图的排序规则相匹配。Otherwise, the operation errors.否则,操作将出错。

Restrictions限制

Restrictions限制Description描述
Transactions事务 An aggregation pipeline cannot use $unionWith inside transactions.聚合管道不能将$unionWith用于事务内部。
Sharded Collection碎片集合 If the $unionWith stage is part of the $lookup pipeline, the $unionWith coll cannot be sharded.如果$unionWith阶段是$lookup管道的一部分,则$unionWith coll不能被切分。
$out The $unionWith pipeline cannot include the $out stage.$unionWith管道不能包括$out阶段。
$merge The $unionWith pipeline cannot include the $merge stage.$unionWith管道不能包含$merge阶段。

Examples示例

Create a Yearly Report from the Union of Quarterly Data Collections从季度数据收集联盟创建年度报告

Create a sample sales2019q1 collection with the following documents:使用以下文档创建sales2019q1样本集合:

db.sales2019q1.insertMany([
  { store: "A", item: "Chocolates", quantity: 150 },
  { store: "B", item: "Chocolates", quantity: 50 },
  { store: "A", item: "Cookies", quantity: 100 },
  { store: "B", item: "Cookies", quantity: 120 },
  { store: "A", item: "Pie", quantity: 10 },
  { store: "B", item: "Pie", quantity: 5 }
])

Create a sample sales2019q2 collection with the following documents:使用以下文档创建sales2019q2样本集合:

db.sales2019q2.insertMany([
  { store: "A", item: "Cheese", quantity: 30 },
  { store: "B", item: "Cheese", quantity: 50 },
  { store: "A", item: "Chocolates", quantity: 125 },
  { store: "B", item: "Chocolates", quantity: 150 },
  { store: "A", item: "Cookies", quantity: 200 },
  { store: "B", item: "Cookies", quantity: 100 },
  { store: "B", item: "Nuts", quantity: 100 },
  { store: "A", item: "Pie", quantity: 30 },
  { store: "B", item: "Pie", quantity: 25 }
])

Create a sample sales2019q3 collection with the following documents:使用以下文档创建sales2019q3样本集合:

db.sales2019q3.insertMany([
  { store: "A", item: "Cheese", quantity: 50 },
  { store: "B", item: "Cheese", quantity: 20 },
  { store: "A", item: "Chocolates", quantity: 125 },
  { store: "B", item: "Chocolates", quantity: 150 },
  { store: "A", item: "Cookies", quantity: 200 },
  { store: "B", item: "Cookies", quantity: 100 },
  { store: "A", item: "Nuts", quantity: 80 },
  { store: "B", item: "Nuts", quantity: 30 },
  { store: "A", item: "Pie", quantity: 50 },
  { store: "B", item: "Pie", quantity: 75 }
])

Create a sample sales2019q4 collection with the following documents:使用以下文档创建sales2019q4样本集合:

db.sales2019q4.insertMany([
  { store: "A", item: "Cheese", quantity: 100, },
  { store: "B", item: "Cheese", quantity: 100},
  { store: "A", item: "Chocolates", quantity: 200 },
  { store: "B", item: "Chocolates", quantity: 300 },
  { store: "A", item: "Cookies", quantity: 500 },
  { store: "B", item: "Cookies", quantity: 400 },
  { store: "A", item: "Nuts", quantity: 100 },
  { store: "B", item: "Nuts", quantity: 200 },
  { store: "A", item: "Pie", quantity: 100 },
  { store: "B", item: "Pie", quantity: 100 }
])

Report 1: All Sales by Quarter and Stores and Items报告1:按季度、门店和商品列出的所有销售额

The following aggregation uses $unionWith to combine documents from all four collections to create a yearly sales report that lists all sales by quarter and stores:以下聚合使用$unionWith合并所有四个集合中的文档,以创建年度销售报告,按季度和门店列出所有销售额:

db.sales2019q1.aggregate( [
   { $set: { _id: "2019Q1" } },
   { $unionWith: { coll: "sales2019q2", pipeline: [ { $set: { _id: "2019Q2" } } ] } },
   { $unionWith: { coll: "sales2019q3", pipeline: [ { $set: { _id: "2019Q3" } } ] } },
   { $unionWith: { coll: "sales2019q4", pipeline: [ { $set: { _id: "2019Q4" } } ] } },
   { $sort: { _id: 1, store: 1, item: 1 } }
] )

Specifically, the aggregation pipeline uses:具体而言,聚合管道使用:

  • a $set stage to update the _id field to contain the quarter. $set阶段更新_id字段以包含季度。That is, the documents from this stage has the form:也就是说,本阶段文件的形式如下:

    { "_id" : "2019Q1", "store" : "A", "item" : "Chocolates", "quantity" : 150 }
    { "_id" : "2019Q1", "store" : "B", "item" : "Chocolates", "quantity" : 50 }
    ...
  • a sequence of $unionWith stages to combine all documents from the four collections; each also using the $set stage on its documents. 一个$unionWith阶段的序列,用于合并四个集合中的所有文档;每个文档都在文档中使用$set阶段。That is, the documents are from all four collections and have the form:也就是说,文件来自所有四个集合,其形式如下:

    { "_id" : "2019Q1", "store" : "A", "item" : "Chocolates", "quantity" : 150 }
    { "_id" : "2019Q1", "store" : "B", "item" : "Chocolates", "quantity" : 50 }
    ...
    { "_id" : "2019Q2", "store" : "A", "item" : "Cheese", "quantity" : 30 }
    { "_id" : "2019Q2", "store" : "B", "item" : "Cheese", "quantity" : 50 }
    ...
    { "_id" : "2019Q3", "store" : "A", "item" : "Cheese", "quantity" : 50 }
    { "_id" : "2019Q3", "store" : "B", "item" : "Cheese", "quantity" : 20 }
    ...
    { "_id" : "2019Q4", "store" : "A", "item" : "Cheese", "quantity" : 100 }
    { "_id" : "2019Q4", "store" : "B", "item" : "Cheese", "quantity" : 100 }
  • a $sort stage to sort by the _id (i.e. the quarter), the store, and item.$sort阶段,按_id(即季度)、storeitem进行排序。

    { "_id" : "2019Q1", "store" : "A", "item" : "Chocolates", "quantity" : 150 }
    { "_id" : "2019Q1", "store" : "A", "item" : "Cookies", "quantity" : 100 }
    { "_id" : "2019Q1", "store" : "A", "item" : "Pie", "quantity" : 10 }
    { "_id" : "2019Q1", "store" : "B", "item" : "Chocolates", "quantity" : 50 }
    { "_id" : "2019Q1", "store" : "B", "item" : "Cookies", "quantity" : 120 }
    { "_id" : "2019Q1", "store" : "B", "item" : "Pie", "quantity" : 5 }
    { "_id" : "2019Q2", "store" : "A", "item" : "Cheese", "quantity" : 30 }
    { "_id" : "2019Q2", "store" : "A", "item" : "Chocolates", "quantity" : 125 }
    { "_id" : "2019Q2", "store" : "A", "item" : "Cookies", "quantity" : 200 }
    { "_id" : "2019Q2", "store" : "A", "item" : "Pie", "quantity" : 30 }
    { "_id" : "2019Q2", "store" : "B", "item" : "Cheese", "quantity" : 50 }
    { "_id" : "2019Q2", "store" : "B", "item" : "Chocolates", "quantity" : 150 }
    { "_id" : "2019Q2", "store" : "B", "item" : "Cookies", "quantity" : 100 }
    { "_id" : "2019Q2", "store" : "B", "item" : "Nuts", "quantity" : 100 }
    { "_id" : "2019Q2", "store" : "B", "item" : "Pie", "quantity" : 25 }
    { "_id" : "2019Q3", "store" : "A", "item" : "Cheese", "quantity" : 50 }
    { "_id" : "2019Q3", "store" : "A", "item" : "Chocolates", "quantity" : 125 }
    { "_id" : "2019Q3", "store" : "A", "item" : "Cookies", "quantity" : 200 }
    { "_id" : "2019Q3", "store" : "A", "item" : "Nuts", "quantity" : 80 }
    { "_id" : "2019Q3", "store" : "A", "item" : "Pie", "quantity" : 50 }
    { "_id" : "2019Q3", "store" : "B", "item" : "Cheese", "quantity" : 20 }
    { "_id" : "2019Q3", "store" : "B", "item" : "Chocolates", "quantity" : 150 }
    { "_id" : "2019Q3", "store" : "B", "item" : "Cookies", "quantity" : 100 }
    { "_id" : "2019Q3", "store" : "B", "item" : "Nuts", "quantity" : 30 }
    { "_id" : "2019Q3", "store" : "B", "item" : "Pie", "quantity" : 75 }
    { "_id" : "2019Q4", "store" : "A", "item" : "Cheese", "quantity" : 100 }
    { "_id" : "2019Q4", "store" : "A", "item" : "Chocolates", "quantity" : 200 }
    { "_id" : "2019Q4", "store" : "A", "item" : "Cookies", "quantity" : 500 }
    { "_id" : "2019Q4", "store" : "A", "item" : "Nuts", "quantity" : 100 }
    { "_id" : "2019Q4", "store" : "A", "item" : "Pie", "quantity" : 100 }
    { "_id" : "2019Q4", "store" : "B", "item" : "Cheese", "quantity" : 100 }
    { "_id" : "2019Q4", "store" : "B", "item" : "Chocolates", "quantity" : 300 }
    { "_id" : "2019Q4", "store" : "B", "item" : "Cookies", "quantity" : 400 }
    { "_id" : "2019Q4", "store" : "B", "item" : "Nuts", "quantity" : 200 }
    { "_id" : "2019Q4", "store" : "B", "item" : "Pie", "quantity" : 100 }

Report 2: Aggregated Yearly Sales by Items报告2:按项目划分的年度总销售额

The following aggregation uses $unionWith to combine documents from all four collections to create a yearly sales report that lists the yearly sales quantity per item:以下聚合使用$unionWith组合来自所有四个集合的文档,以创建年度销售报告,其中列出了每个项目的年度销售数量:

db.sales2019q1.aggregate( [
   { $unionWith: "sales2019q2" },
   { $unionWith: "sales2019q3" },
   { $unionWith: "sales2019q4" },
   { $group: { _id: "$item", total: { $sum: "$quantity" } } },
   { $sort: { total: -1 }}
] )
  • The sequence of $unionWith stages retrieve documents from the specified collections into the pipeline:$unionWith阶段将指定集合中的文档检索到管道中的顺序:

    { "_id" : ObjectId("5e505848c15f157c0793fec7"), "store" : "A", "item" : "Chocolates", "quantity" : 150 }
    { "_id" : ObjectId("5e505848c15f157c0793fec8"), "store" : "B", "item" : "Chocolates", "quantity" : 50 }
    { "_id" : ObjectId("5e505848c15f157c0793fec9"), "store" : "A", "item" : "Cookies", "quantity" : 100 }
    { "_id" : ObjectId("5e505848c15f157c0793feca"), "store" : "B", "item" : "Cookies", "quantity" : 120 }
    { "_id" : ObjectId("5e505848c15f157c0793fecb"), "store" : "A", "item" : "Pie", "quantity" : 10 }
    { "_id" : ObjectId("5e505848c15f157c0793fecc"), "store" : "B", "item" : "Pie", "quantity" : 5 }
    { "_id" : ObjectId("5e50584bc15f157c0793fecd"), "store" : "A", "item" : "Cheese", "quantity" : 30 }
    { "_id" : ObjectId("5e50584bc15f157c0793fece"), "store" : "B", "item" : "Cheese", "quantity" : 50 }
    { "_id" : ObjectId("5e50584bc15f157c0793fecf"), "store" : "A", "item" : "Chocolates", "quantity" : 125 }
    { "_id" : ObjectId("5e50584bc15f157c0793fed0"), "store" : "B", "item" : "Chocolates", "quantity" : 150 }
    { "_id" : ObjectId("5e50584bc15f157c0793fed1"), "store" : "A", "item" : "Cookies", "quantity" : 200 }
    { "_id" : ObjectId("5e50584bc15f157c0793fed2"), "store" : "B", "item" : "Cookies", "quantity" : 100 }
    ...
  • The $group stage groups by the item field and uses $sum to calculate the yearly total sales quantity per item:$group阶段按item字段分组,并使用$sum计算每个item的年度总销售数量:

    { "_id" : "Cookies", "total" : 1720 }
    { "_id" : "Pie", "total" : 395 }
    { "_id" : "Cheese", "total" : 350 }
    { "_id" : "Chocolates", "total" : 1250 }
    { "_id" : "Nuts", "total" : 510 }
  • The $sort stage orders the documents by descending total.$sort阶段按total降序排列文档。

    { "_id" : "Cookies", "total" : 1940 }
    { "_id" : "Chocolates", "total" : 1450 }
    { "_id" : "Nuts", "total" : 510 }
    { "_id" : "Pie", "total" : 410 }
    { "_id" : "Cheese", "total" : 350 }

Alternatively, you could specify the $group stage within each $unionWith stage:或者,您可以在每个$unionWith阶段中指定$group阶段:

db.sales2019q1.aggregate( [
   { $group: { _id: "$item", total: { $sum: "$quantity" } } },
   { $unionWith: { coll: "sales2019q2", pipeline: [ { $group: { _id: "$item", total: { $sum: "$quantity" } } } ] } },
   { $unionWith: { coll: "sales2019q3", pipeline: [ { $group: { _id: "$item", total: { $sum: "$quantity" } } } ] } },
   { $unionWith: { coll: "sales2019q4", pipeline: [ { $group: { _id: "$item", total: { $sum: "$quantity" } } } ] } },
   { $group: { _id: "$_id", total: { $sum: "$total" } } },
   { $sort: { total: -1 }}
] )
  • The first $group groups the 2019q1 sales totals by items:第一个$group按项目对2019年第一季度的销售总额进行分组:

    { "_id" : "Pie", "total" : 30 }
    { "_id" : "Cookies", "total" : 440 }
    { "_id" : "Chocolates", "total" : 400 }
  • The sequence of $unionWith stages groups the sales total by the items from the specified collections into the pipeline:$unionWith阶段的顺序将指定系列中的商品的销售总额分组到管道中:

    { "_id" : "Cookies", "total" : 440 }
    { "_id" : "Chocolates", "total" : 400 }
    { "_id" : "Pie", "total" : 30 }
    { "_id" : "Chocolates", "total" : 275 }  // From sales2019q2
    { "_id" : "Nuts", "total" : 100 }        // From sales2019q2
    { "_id" : "Cheese", "total" : 80 }       // From sales2019q2
    { "_id" : "Pie", "total" : 55 }          // From sales2019q2
    { "_id" : "Cookies", "total" : 300 }     // From sales2019q2
    ...                                      // Results from sales2019 q3 and q4 omitted for brevity
  • The last $group stage groups these quarterly groupings:最后一个$group阶段将这些季度分组:

    { "_id" : "Cookies", "total" : 1720 }
    { "_id" : "Pie", "total" : 395 }
    { "_id" : "Cheese", "total" : 350 }
    { "_id" : "Chocolates", "total" : 1250 }
    { "_id" : "Nuts", "total" : 510 }
  • The $sort stage orders the documents by descending total.$sort阶段按total降序排列文档。

    { "_id" : "Cookies", "total" : 1940 }
    { "_id" : "Chocolates", "total" : 1450 }
    { "_id" : "Nuts", "total" : 510 }
    { "_id" : "Pie", "total" : 410 }
    { "_id" : "Cheese", "total" : 350 }