$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