$unionWith – MongoDB相当于UNION ALL
如果您熟悉 SQL,则可能知道该子句,该子句将两个查询的结果连接成一个结果集。特别是,包括重复项。[UNION](https://database.guide/sql-union-clause-for-beginners/ "SQL UNION Clause for Beginners")``UNION ALL
在MongoDB中,我们可以使用聚合管道阶段来实现与产生相同的效果。该阶段执行两个集合的并集 - 它将两个集合的管道结果合并到单个结果集中。它包括重复项。$unionWith``UNION ALL``$unionWith
例
假设我们创建两个集合;一个叫,另一个叫.我们将以下文档插入其中:cats``dogs
db.cats.insertMany([
{ _id: 1, name: "Fluffy", type: "Cat", weight: 5 },
{ _id: 2, name: "Scratch", type: "Cat", weight: 3 },
{ _id: 3, name: "Meow", type: "Cat", weight: 7 }
])
db.dogs.insertMany([
{ _id: 1, name: "Wag", type: "Dog", weight: 20 },
{ _id: 2, name: "Bark", type: "Dog", weight: 10 },
{ _id: 3, name: "Fluffy", type: "Dog", weight: 40 }
])
现在,我们可以针对这些集合运行查询,并使用阶段来组合每个查询的结果。$unionWith
例:
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
结果:
{ “_id” : 3, “name” : “Meow”, “type” : “Cat”, “weight” : 7 } { “_id” : 1, “name” : “Fluffy”, “type” : “Cat”, “weight” : 5 } { “_id” : 2, “name” : “Scratch”, “type” : “Cat”, “weight” : 3 } { “_id” : 3, “name” : “Fluffy”, “type” : “Dog”, “weight” : 40 } { “_id” : 1, “name” : “Wag”, “type” : “Dog”, “weight” : 20 } { “_id” : 2, “name” : “Bark”, “type” : “Dog”, “weight” : 10 }
在此示例中,每个文档都有一个带有 or 的类型字段,因此很明显哪个文档来自哪个集合。cat``dog
但是,如果文档没有类型字段,那么就很难确定一个集合在哪里结束,另一个集合从哪里开始。在这种情况下,我们可以在阶段使用字符串文字来表示集合名称。$set
例:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
结果:
{ “_id” : “cat”, “name” : “Meow”, “type” : “Cat”, “weight” : 7 } { “_id” : “cat”, “name” : “Fluffy”, “type” : “Cat”, “weight” : 5 } { “_id” : “cat”, “name” : “Scratch”, “type” : “Cat”, “weight” : 3 } { “_id” : “dog”, “name” : “Fluffy”, “type” : “Dog”, “weight” : 40 } { “_id” : “dog”, “name” : “Wag”, “type” : “Dog”, “weight” : 20 } { “_id” : “dog”, “name” : “Bark”, “type” : “Dog”, “weight” : 10 }
跨集合排序
在前面的示例中,猫和狗的排序方式将它们分为两个不同的组;先是猫,然后是狗。这主要是因为我们首先在现场排序。type
但是我们可以在任何其他领域对其进行排序,这可能会导致猫和狗被组合在一起。
例:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { name: 1 } }
] )
结果:
{ “_id” : “dog”, “name” : “Bark”, “type” : “Dog”, “weight” : 10 } { “_id” : “cat”, “name” : “Fluffy”, “type” : “Cat”, “weight” : 5 } { “_id” : “dog”, “name” : “Fluffy”, “type” : “Dog”, “weight” : 40 } { “_id” : “cat”, “name” : “Meow”, “type” : “Cat”, “weight” : 7 } { “_id” : “cat”, “name” : “Scratch”, “type” : “Cat”, “weight” : 3 } { “_id” : “dog”, “name” : “Wag”, “type” : “Dog”, “weight” : 20 }
预测
可以使用该阶段指定要传递到管道中的下一阶段的字段。例如,因此可以减少查询返回的字段数。$project
例:
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} }
] )
结果:
{ “name” : “Fluffy” } { “name” : “Scratch” } { “name” : “Meow” } { “name” : “Wag” } { “name” : “Bark” } { “name” : “Fluffy” }
删除重复项
您可以使用该阶段从结果中消除冗余重复项。$group
例如,前面的查询返回了两只名为 Fluffy 的宠物。我们可以向该查询添加一个阶段以消除冗余重复项,以便只返回一个 Fluffy。$group
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} },
{ $group: { _id: "$name" } }
] )
结果:
{ “_id” : “Meow” } { “_id” : “Bark” } { “_id” : “Scratch” } { “_id” : “Wag” } { “_id” : “Fluffy” }
这一次,只返回了一个毛茸茸的。
不匹配的列
MongoDB相对于SQL的优势之一是它可以与不匹配的列一起使用。$unionWith``UNION ALL
SQL 子句要求:UNION
- 两个查询返回相同数量的列
- 列顺序相同
- 匹配的列必须是兼容的数据类型
MongoDB阶段不会施加这些限制。$unionWith
因此,我们可以用来做这样的事情:$unionWith
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "employees", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, salary: -1 } }
] )
结果:
{ “_id” : 2, “name” : “Sarah”, “salary” : 128000 } { “_id” : 5, “name” : “Beck”, “salary” : 82000 } { “_id” : 4, “name” : “Chris”, “salary” : 45000 } { “_id” : 3, “name” : “Fritz”, “salary” : 25000 } { “_id” : 1, “name” : “Fluffy”, “type” : “Cat”, “weight” : 5 } { “_id” : 2, “name” : “Scratch”, “type” : “Cat”, “weight” : 3 } { “_id” : 3, “name” : “Meow”, “type” : “Cat”, “weight” : 7 }
在本例中,我们将集合与集合联接在一起。该集合没有与集合相同的字段,但这很好 - 它仍然有效。cats``employees``employees``cats