文档菜单
文档首页
/
MongoDB 手册
/ / /

$unionWith (aggregation)

本页面

  • 定义
  • 语法
  • 注意事项
  • 重复结果
  • $unionWith 分片集合
  • 排序规则
  • Atlas 搜索支持
  • 限制
  • 示例
  • 从年度数据集合的并集中创建销售报告
  • 报告1:按年份、商店和商品的所有销售
  • 报告2:按商品汇总的销售
  • 使用指定的文档创建并集
  • 子管道中的命名空间
$unionWith

已更改版本8.0.

将两个聚合操作合并为一个结果集。 $unionWith 将合并的结果集(包括重复项)输出到下一阶段。

合并结果集文档的输出顺序是不确定的。

$unionWith 阶段具有以下语法

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

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

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

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

字段
必要性
描述
coll
如果省略 pipeline 则是必需的。否则是可选的。

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

如果您省略了coll字段,您必须指定一个具有以下第一阶段的pipeline字段:$documents.

如果省略了coll,则为必选。否则为可选。

应用于输入文档的聚合管道。

  • 如果您指定了coll,则管道应用于coll中的文档。

  • 如果您省略了coll,则管道应用于管道的$documents阶段。例如,请参阅创建具有指定文档的联合。

管道不能包含$out$merge阶段。从v6.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" }

要删除重复项,您可以在按 state 字段分组的基础上包含一个 $group 阶段

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 pipeline 的一部分,则 $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() 包含一个 collation 文档,则该校对用于操作,忽略任何其他校对。

如果 db.collection.aggregate() 不包含 collation 文档,则 db.collection.aggregate() 方法使用 db.collection.aggregate() 在其上运行的顶层集合/视图的校对。

  • 如果 $unionWith coll 是一个集合,则忽略其校对。

  • 如果 $unionWith coll 是一个 视图,则其校对必须与顶层集合/视图匹配。否则,操作会出错。

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

[{
"$unionWith": {
"coll": <collection-name>,
"pipeline": [{
"$search": {
"<operator>": {
<operator-specification>
}
},
...
}]
}
}]
[{
"$unionWith": {
"coll": <collection-name>,
"pipeline": [{
"$searchMeta": {
"<collector>": {
<collector-specification>
}
},
...
}]
}
}]

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

限制
描述
聚合管道不能在事务中使用 $unionWith
分片集合
如果$unionWith阶段是$lookup pipeline的一部分,则$unionWith coll不能进行分片。
$unionWith pipeline不能包含$out阶段。
$unionWith pipeline不能包含$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阶段。

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

管道输出

{ "_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 }

您可以使用 $unionWith 来对在 pipeline 字段中指定的文档进行联合操作。当您在 pipeline 字段中指定一个 $documents 阶段时,您将执行与未存储在单独集合中的文档的联合。

创建一个 cakeFlavors 集合

db.cakeFlavors.insertMany( [
{ _id: 1, flavor: "chocolate" },
{ _id: 2, flavor: "strawberry" },
{ _id: 3, flavor: "cherry" }
] )

以下 $unionWith 操作执行了在 pipeline 字段中指定的文档的联合操作

db.cakeFlavors.aggregate( [
{
$unionWith: {
pipeline: [
{
$documents: [
{ _id: 4, flavor: "orange" },
{ _id: 5, flavor: "vanilla", price: 20 }
]
}
]
}
}
] )

输出

[
{ _id: 1, flavor: 'chocolate' },
{ _id: 2, flavor: 'strawberry' },
{ _id: 3, flavor: 'cherry' },
{ _id: 4, flavor: 'orange' },
{ _id: 5, flavor: 'vanilla', price: 20 }
]

从 MongoDB 8.0 开始,对 $lookup$unionWith 中的子管道命名空间进行验证,以确保正确使用 fromcoll 字段。

  • 对于 $lookup,如果您使用了一个不需要指定集合的子管道阶段,则省略 from 字段。例如,一个 $documents 阶段。

  • 类似地,对于 $unionWith,省略 coll 字段。

不变的行为

  • 对于以集合阶段开始的 $lookup,例如 $match$collStats 子管道,您必须包含 from 字段并指定集合。

  • 同样,对于$unionWith,包括coll字段并指定集合。

以下场景展示了一个例子。

创建一个 cakeFlavors 集合

db.cakeFlavors.insertMany( [
{ _id: 1, flavor: "chocolate" },
{ _id: 2, flavor: "strawberry" },
{ _id: 3, flavor: "cherry" }
] )

从MongoDB 8.0版本开始,以下示例返回一个错误,因为它包含一个无效的coll字段

db.cakeFlavors.aggregate( [ {
$unionWith: {
coll: "cakeFlavors",
pipeline: [ { $documents: [] } ] }
} ] )

在MongoDB 8.0之前的版本中,之前的示例可以运行。

有关具有有效coll字段的示例,请参阅重复结果。

返回

$sortByCount