Docs 菜单

Docs 主页开发应用程序MongoDB Manual

$unionWith(聚合)

在此页面上

  • 定义
  • 语法
  • 考虑因素
  • 重复结果
  • $unionWith 分片集合
  • 排序规则
  • Atlas Search 支持
  • 限制
  • 举例
  • 从年度数据集合联合创建销售报告
  • 报告 1:按年份、商店和商品列出的所有销售额
  • 报告 2:按商品分类的合计销售额
$unionWith

执行两个集合的并集。 $unionWith将两个集合的管道结果合并到一个结果集中。该阶段将合并的结果集(包括重复项)输出到下一阶段。

未指定合并结果集文档的输出顺序。

$unionWith阶段采用以下语法:

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

要包含指定集合中的所有文档而不进行任何处理,您可以使用简化的形式:

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

$unionWith阶段接受包含以下字段的文档:

字段
说明
coll

您希望将其管道结果包含在结果集中的集合或视图。

可选。要应用于指定集合的聚合管道

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

管道不能包括$out$merge阶段。从 v 6开始。 0中, pipeline可以包含Atlas Search $search阶段作为管道内的第一阶段。要了解更多信息,请参阅Atlas Search 支持。

$unionWith操作对应于以下 SQL 语句:

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

上一阶段和$unionWith阶段的合并结果可能包含重复项。

例如,创建一个 suppliers 集合和一个 warehouses 集合:

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" },
])

以下聚合组合了来自 supplierswarehouse 集合的 state 字段投影结果。

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

结果集包含重复项:

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

要移除重复项,可以包括一个 $group 阶段,按照 state 字段进行分组:

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

结果集不再包含重复项:

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

如果$unionWith阶段是$lookup 管道的一部分,则无法对$unionWith coll进行分片。例如,在以下聚合操作中,无法对inventory_q1集合进行分片:

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

如果 db.collection.aggregate() 包含排序规则,则会使用该排序规则进行操作,忽略任何其他排序规则。

如果 db.collection.aggregate() 不包含排序规则db.collection.aggregate() 方法将使用运行 db.collection.aggregate() 的顶级集合/视图的排序规则:

  • 如果$unionWith coll是集合,则忽略其排序规则。

  • 如果$unionWith coll视图,则其排序规则必须与顶级集合/视图的排序规则匹配。否则,操作将出错。

从 MongoDB 6开始。 0 ,您可以在$unionWith管道中指定Atlas Search $search$searchMeta阶段来搜索 Atlas 集群上的集合。 $search$searchMeta阶段必须是$unionWith管道内的第一阶段。

要查看$unionWith$search的示例,请参阅 Atlas Search 教程使用 $unionWith 运行 Atlas Search $search 查询。

限制
说明
聚合管道不能在$unionWith 事务 内部使用 。
分片集合
如果$unionWith阶段是$lookup 管道的一部分,则无法对$unionWith coll进行分片。
$unionWith 管道不能包含$out阶段。
$unionWith 管道不能包含$merge阶段。

以下示例使用$unionWith阶段合并数据并返回多个集合的结果。在这些示例中,每个集合都包含一年的销售数据。

  1. 使用以下文档创建 sales_2017 集合:

    db.sales_2017.insertMany( [
    { store: "General Store", item: "Chocolates", quantity: 150 },
    { store: "ShopMart", item: "Chocolates", quantity: 50 },
    { store: "General Store", item: "Cookies", quantity: 100 },
    { store: "ShopMart", item: "Cookies", quantity: 120 },
    { store: "General Store", item: "Pie", quantity: 10 },
    { store: "ShopMart", item: "Pie", quantity: 5 }
    ] )
  2. 使用以下文档创建 sales_2018 集合:

    db.sales_2018.insertMany( [
    { store: "General Store", item: "Cheese", quantity: 30 },
    { store: "ShopMart", item: "Cheese", quantity: 50 },
    { store: "General Store", item: "Chocolates", quantity: 125 },
    { store: "ShopMart", item: "Chocolates", quantity: 150 },
    { store: "General Store", item: "Cookies", quantity: 200 },
    { store: "ShopMart", item: "Cookies", quantity: 100 },
    { store: "ShopMart", item: "Nuts", quantity: 100 },
    { store: "General Store", item: "Pie", quantity: 30 },
    { store: "ShopMart", item: "Pie", quantity: 25 }
    ] )
  3. 使用以下文档创建 sales_2019 集合:

    db.sales_2019.insertMany( [
    { store: "General Store", item: "Cheese", quantity: 50 },
    { store: "ShopMart", item: "Cheese", quantity: 20 },
    { store: "General Store", item: "Chocolates", quantity: 125 },
    { store: "ShopMart", item: "Chocolates", quantity: 150 },
    { store: "General Store", item: "Cookies", quantity: 200 },
    { store: "ShopMart", item: "Cookies", quantity: 100 },
    { store: "General Store", item: "Nuts", quantity: 80 },
    { store: "ShopMart", item: "Nuts", quantity: 30 },
    { store: "General Store", item: "Pie", quantity: 50 },
    { store: "ShopMart", item: "Pie", quantity: 75 }
    ] )
  4. 使用以下文档创建 sales_2020 集合:

    db.sales_2020.insertMany( [
    { store: "General Store", item: "Cheese", quantity: 100, },
    { store: "ShopMart", item: "Cheese", quantity: 100},
    { store: "General Store", item: "Chocolates", quantity: 200 },
    { store: "ShopMart", item: "Chocolates", quantity: 300 },
    { store: "General Store", item: "Cookies", quantity: 500 },
    { store: "ShopMart", item: "Cookies", quantity: 400 },
    { store: "General Store", item: "Nuts", quantity: 100 },
    { store: "ShopMart", item: "Nuts", quantity: 200 },
    { store: "General Store", item: "Pie", quantity: 100 },
    { store: "ShopMart", item: "Pie", quantity: 100 }
    ] )

以下聚合创建了一份年度销售报告,其中按季度和门店列出了所有销售额。管道使用$unionWith合并来自所有四个集合的文档:

db.sales_2017.aggregate( [
{ $set: { _id: "2017" } },
{ $unionWith: { coll: "sales_2018", pipeline: [ { $set: { _id: "2018" } } ] } },
{ $unionWith: { coll: "sales_2019", pipeline: [ { $set: { _id: "2019" } } ] } },
{ $unionWith: { coll: "sales_2020", pipeline: [ { $set: { _id: "2020" } } ] } },
{ $sort: { _id: 1, store: 1, item: 1 } }
] )

具体来说,聚合管道使用:

  • $set 阶段,用于更新 _id 字段以包含年份。

  • 一系列$unionWith阶段,用于合并四个集合中的所有文档,每个集合还对其文档使用$set阶段。

  • _id (年份)、 storeitem排序的$sort阶段。

管道输出:

{ "_id" : "2017", "store" : "General Store", "item" : "Chocolates", "quantity" : 150 }
{ "_id" : "2017", "store" : "General Store", "item" : "Cookies", "quantity" : 100 }
{ "_id" : "2017", "store" : "General Store", "item" : "Pie", "quantity" : 10 }
{ "_id" : "2017", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 50 }
{ "_id" : "2017", "store" : "ShopMart", "item" : "Cookies", "quantity" : 120 }
{ "_id" : "2017", "store" : "ShopMart", "item" : "Pie", "quantity" : 5 }
{ "_id" : "2018", "store" : "General Store", "item" : "Cheese", "quantity" : 30 }
{ "_id" : "2018", "store" : "General Store", "item" : "Chocolates", "quantity" : 125 }
{ "_id" : "2018", "store" : "General Store", "item" : "Cookies", "quantity" : 200 }
{ "_id" : "2018", "store" : "General Store", "item" : "Pie", "quantity" : 30 }
{ "_id" : "2018", "store" : "ShopMart", "item" : "Cheese", "quantity" : 50 }
{ "_id" : "2018", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 150 }
{ "_id" : "2018", "store" : "ShopMart", "item" : "Cookies", "quantity" : 100 }
{ "_id" : "2018", "store" : "ShopMart", "item" : "Nuts", "quantity" : 100 }
{ "_id" : "2018", "store" : "ShopMart", "item" : "Pie", "quantity" : 25 }
{ "_id" : "2019", "store" : "General Store", "item" : "Cheese", "quantity" : 50 }
{ "_id" : "2019", "store" : "General Store", "item" : "Chocolates", "quantity" : 125 }
{ "_id" : "2019", "store" : "General Store", "item" : "Cookies", "quantity" : 200 }
{ "_id" : "2019", "store" : "General Store", "item" : "Nuts", "quantity" : 80 }
{ "_id" : "2019", "store" : "General Store", "item" : "Pie", "quantity" : 50 }
{ "_id" : "2019", "store" : "ShopMart", "item" : "Cheese", "quantity" : 20 }
{ "_id" : "2019", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 150 }
{ "_id" : "2019", "store" : "ShopMart", "item" : "Cookies", "quantity" : 100 }
{ "_id" : "2019", "store" : "ShopMart", "item" : "Nuts", "quantity" : 30 }
{ "_id" : "2019", "store" : "ShopMart", "item" : "Pie", "quantity" : 75 }
{ "_id" : "2020", "store" : "General Store", "item" : "Cheese", "quantity" : 100 }
{ "_id" : "2020", "store" : "General Store", "item" : "Chocolates", "quantity" : 200 }
{ "_id" : "2020", "store" : "General Store", "item" : "Cookies", "quantity" : 500 }
{ "_id" : "2020", "store" : "General Store", "item" : "Nuts", "quantity" : 100 }
{ "_id" : "2020", "store" : "General Store", "item" : "Pie", "quantity" : 100 }
{ "_id" : "2020", "store" : "ShopMart", "item" : "Cheese", "quantity" : 100 }
{ "_id" : "2020", "store" : "ShopMart", "item" : "Chocolates", "quantity" : 300 }
{ "_id" : "2020", "store" : "ShopMart", "item" : "Cookies", "quantity" : 400 }
{ "_id" : "2020", "store" : "ShopMart", "item" : "Nuts", "quantity" : 200 }
{ "_id" : "2020", "store" : "ShopMart", "item" : "Pie", "quantity" : 100 }

以下聚合创建了一份销售报告,其中列出了每个商品的销售数量。该管道使用$unionWith来合并所有四年的文档:

db.sales_2017.aggregate( [
{ $unionWith: "sales_2018" },
{ $unionWith: "sales_2019" },
{ $unionWith: "sales_2020" },
{ $group: { _id: "$item", total: { $sum: "$quantity" } } },
{ $sort: { total: -1 } }
] )
  • $unionWith阶段序列将指定集合中的文档检索到管道中:

  • $group 阶段按 item 字段进行分组,并使用 $sum 计算每个 item 的总销售量。

  • $sort阶段按降序total 排列文档。

管道输出:

{ "_id" : "Cookies", "total" : 1720 }
{ "_id" : "Chocolates", "total" : 1250 }
{ "_id" : "Nuts", "total" : 510 }
{ "_id" : "Pie", "total" : 395 }
{ "_id" : "Cheese", "total" : 350 }
← $sortByCount(聚合)