使用 MongoDB 将两个集合合并为一个集合
- 使用 MongoDB 将两个集合合并为一个集合
-
使用
$lookup
聚合阶段将两个集合合二为一 -
使用
pipeline
运算符根据指定条件将两个集合合并为一个 -
在附加到结果文档之前使用
$unwind
运算符来平面数组 -
在聚合查询中使用
$project
过滤器阶段将两个集合合二为一 - 使用 Compass 连接两个集合(MongoDB 的图形界面)
今天,我们将使用 $lookup
聚合阶段、pipeline
和 $unwind
运算符、$project
过滤阶段和 MongoDB Compass 将两个集合合并为一个集合。
使用 MongoDB 将两个集合合并为一个集合
我们有不同的方法可以使用 MongoDB 将两个集合组合成一个集合。其中一些在下面给出,我们将在本教程中介绍。
- 使用
$lookup
聚合阶段加入两个集合 - 使用
pipeline
运算符根据指定条件连接两个集合 - 在将数组附加到结果文档之前,使用
$unwind
运算符对数组进行展平 - 在聚合查询中使用
$project
过滤阶段来连接两个集合 - 使用指南针连接两个集合(MongoDB 的图形界面)
对于上述所有场景,我们必须有一个包含两个集合(与 MySQL 中的表相同)的数据库,其中填充了文档(与 MySQL 中的记录相同)。我们使用以下查询完成了这项工作;你也可以这样做。
创建两个名为 usersInformation
和 userAddress
的集合,它们位于 users
数据库中。此外,使用以下文档填充它们。
创建数据库和集合:
> use users
> db.createCollection('userInformation')
> db.createCollection('userAddress')
用两个文档填充 userInformation
集合:
> db.userInformation.insertMany(
[
{
fullname: 'Mehvish Ashiq',
age: 30,
gender: 'Female',
nationality: 'Pakistani'
},
{
fullname: 'James Daniel',
age: 45,
sex: 'male',
nationality: 'Canadian'
}
]
)
用两个文档填充 userAddress
集合:
> db.userAddress.insertMany(
[
{
fullname: 'Mehvish Ashiq',
block_number: 22,
street: 'Johar Town Street',
city: 'Lahore'
},
{
fullname: 'James Daniel',
block_number: 30,
street: 'Saint-Denis Street',
city: 'Montreal'
}
]
)
我们使用 insertMany()
函数插入多个文档。现在,我们可以使用下面的命令来查看两个集合的数据。
在下面的代码片段中,pretty()
方法显示了干净且格式化的输出,这在 shell 上很容易理解。
显示来自 userInformation
的文档:
> db.userInformation.find().pretty()
输出:
{
"_id" : ObjectId("628bc4a45c544feccff5a566"),
"fullname" : "Mehvish Ashiq",
"age" : 30,
"gender" : "Female",
"nationality" : "Pakistani"
}
{
"_id" : ObjectId("628bc4a45c544feccff5a567"),
"fullname" : "James Daniel",
"age" : 45,
"sex" : "male",
"nationality" : "Canadian"
}
显示来自 userAddress
的文档:
> db.userAddress.find().pretty()
输出:
{
"_id" : ObjectId("628bc4ae5c544feccff5a568"),
"fullname" : "Mehvish Ashiq",
"block_number" : 22,
"street" : "Johar Town Street",
"city" : "Lahore"
}
{
"_id" : ObjectId("628bc4ae5c544feccff5a569"),
"fullname" : "James Daniel",
"block_number" : 30,
"street" : "Saint-Denis Street",
"city" : "Montreal"
}
两个集合必须在同一个数据库中才能使用 $lookup
聚合阶段。一旦两个集合都准备好了,我们可以根据我们的场景使用各种查询来连接两个集合的数据。
使用 $lookup
聚合阶段将两个集合合二为一
示例代码:
> db.userInformation.aggregate([
{ $lookup:
{
from: 'userAddress',
localField: 'fullname',
foreignField: 'fullname',
as: 'address'
}
}
]).pretty();
输出:
{
"_id" : ObjectId("628bc4a45c544feccff5a566"),
"fullname" : "Mehvish Ashiq",
"age" : 30,
"gender" : "Female",
"nationality" : "Pakistani",
"address" : [
{
"_id" : ObjectId("628bc4ae5c544feccff5a568"),
"fullname" : "Mehvish Ashiq",
"block_number" : 22,
"street" : "Johar Town Street",
"city" : "Lahore"
}
]
}
{
"_id" : ObjectId("628bc4a45c544feccff5a567"),
"fullname" : "James Daniel",
"age" : 45,
"sex" : "male",
"nationality" : "Canadian",
"address" : [
{
"_id" : ObjectId("628bc4ae5c544feccff5a569"),
"fullname" : "James Daniel",
"block_number" : 30,
"street" : "Saint-Denis Street",
"city" : "Montreal"
}
]
}
在 MongoDB 数据库中,$lookup
聚合阶段执行与其他集合的左外连接,并从连接的文档中过滤信息(数据)。例如,我们使用查询来获取所有用户的信息及其地址。
$lookup
函数接受四个字段。首先是 from
字段,我们在其中指定应该与另一个集合连接的集合。
第二个是 localField
字段。它是 from
字段中指定的集合的输入文档的属性(字段)之一。
它用于对集合文档中的 localField
与 foreignField
执行匹配。
类似地,名为 foreignField
的第三个字段也对集合文档中的 foreignField
与 localField
执行相等匹配。
我们为第四个字段 as
写下新数组的名称。有关 $lookup
聚合阶段的说明,请参见以下说明。
使用 pipeline
运算符根据指定条件将两个集合合并为一个
示例代码:
> db.userInformation.aggregate([{
$lookup:{
from: 'userAddress',
let: {full_name: '$fullname'},
pipeline: [{
$match: {
$expr: {
$eq: ['$fullname', '$$full_name']
}
}
}],
as: 'addressInfo'
}
}]).pretty()
输出:
{
"_id" : ObjectId("628bc4a45c544feccff5a566"),
"fullname" : "Mehvish Ashiq",
"age" : 30,
"gender" : "Female",
"nationality" : "Pakistani",
"addressInfo" : [
{
"_id" : ObjectId("628bc4ae5c544feccff5a568"),
"fullname" : "Mehvish Ashiq",
"block_number" : 22,
"street" : "Johar Town Street",
"city" : "Lahore"
}
]
}
{
"_id" : ObjectId("628bc4a45c544feccff5a567"),
"fullname" : "James Daniel",
"age" : 45,
"sex" : "male",
"nationality" : "Canadian",
"addressInfo" : [
{
"_id" : ObjectId("628bc4ae5c544feccff5a569"),
"fullname" : "James Daniel",
"block_number" : 30,
"street" : "Saint-Denis Street",
"city" : "Montreal"
}
]
}
当我们想要基于特定条件连接两个集合时,我们可以使用带有 $lookup
的 pipeline
运算符(就像我们在 MySQL 中使用 WHERE
子句一样)。
例如,我们正在加入来自 userAddress
的 fullname
等于 userInformation
中的 fullname
的集合。
在附加到结果文档之前使用 $unwind
运算符来平面数组
示例代码:
> db.userInformation.aggregate([
{ $lookup:
{
from: 'userAddress',
localField: 'fullname',
foreignField: 'fullname',
as: 'address'
}
},
{
$unwind: '$address'
}
]).pretty();
输出:
{
"_id" : ObjectId("628bc4a45c544feccff5a566"),
"fullname" : "Mehvish Ashiq",
"age" : 30,
"gender" : "Female",
"nationality" : "Pakistani",
"address" : {
"_id" : ObjectId("628bc4ae5c544feccff5a568"),
"fullname" : "Mehvish Ashiq",
"block_number" : 22,
"street" : "Johar Town Street",
"city" : "Lahore"
}
}
{
"_id" : ObjectId("628bc4a45c544feccff5a567"),
"fullname" : "James Daniel",
"age" : 45,
"sex" : "male",
"nationality" : "Canadian",
"address" : {
"_id" : ObjectId("628bc4ae5c544feccff5a569"),
"fullname" : "James Daniel",
"block_number" : 30,
"street" : "Saint-Denis Street",
"city" : "Montreal"
}
}
$unwind
运算符什么也不做,只是在将数组附加到结果文档之前将其展平。 $unwind
运算符的根本区别在于它将具有单个元素的数组转换为扁平对象,即元素本身。
请记住,此元素的名称不会更改。当元素为数组形式时,它与以前相同。
使用和不使用 $unwind
运算符执行上述查询并观察 address
字段。
在聚合查询中使用 $project
过滤器阶段将两个集合合二为一
在使用 $project
加入集合之前,让我们了解它的重要性。例如,如果我们不想将名为 userAddress
的整个集合与 userInformation
连接起来,我们只希望连接 city
和 street
字段。
在这种情况下,我们需要使用 $addFields
阶段。我们使用此阶段将数组/对象中的任何字段或多个字段加入/分配到文档的根级别。
因此,我们执行以下查询以从 userAddress
集合中检索 city
和 street
。
示例代码:
> db.userInformation.aggregate([
{ $lookup:
{
from: 'userAddress',
localField: 'fullname',
foreignField: 'fullname',
as: 'address'
}
},
{
$unwind: '$address'
},
{
$addFields: {
street: '$address.street',
city: '$address.city'
}
}
]).pretty();
输出:
{
"_id" : ObjectId("628bc4a45c544feccff5a566"),
"fullname" : "Mehvish Ashiq",
"age" : 30,
"gender" : "Female",
"nationality" : "Pakistani",
"address" : {
"_id" : ObjectId("628bc4ae5c544feccff5a568"),
"fullname" : "Mehvish Ashiq",
"block_number" : 22,
"street" : "Johar Town Street",
"city" : "Lahore"
},
"street" : "Johar Town Street",
"city" : "Lahore"
}
{
"_id" : ObjectId("628bc4a45c544feccff5a567"),
"fullname" : "James Daniel",
"age" : 45,
"sex" : "male",
"nationality" : "Canadian",
"address" : {
"_id" : ObjectId("628bc4ae5c544feccff5a569"),
"fullname" : "James Daniel",
"block_number" : 30,
"street" : "Saint-Denis Street",
"city" : "Montreal"
},
"street" : "Saint-Denis Street",
"city" : "Montreal"
}
仔细关注上面给出的输出。我们得到了街道
和城市
吗?是的,我们在文档的根级别获得了 street
和 city
,但也有我们现在不需要的 address
对象。
这就是 $project
过滤阶段的用武之地。它指定我们应该在结果文档中包含哪些字段。
请参阅以下查询以获得更好的理解。
示例代码:
> db.userInformation.aggregate([
{ $lookup:
{
from: 'userAddress',
localField: 'fullname',
foreignField: 'fullname',
as: 'address'
}
},
{
$unwind: '$address'
},
{
$addFields: {
street: '$address.street',
city: '$address.city'
}
},
{
$project: {
fullname: 1,
age: 1,
gender: 1,
street: 1,
city: 1
}
}
]).pretty();
输出:
{
"_id" : ObjectId("628bc4a45c544feccff5a566"),
"fullname" : "Mehvish Ashiq",
"age" : 30,
"gender" : "Female",
"street" : "Johar Town Street",
"city" : "Lahore"
}
{
"_id" : ObjectId("628bc4a45c544feccff5a567"),
"fullname" : "James Daniel",
"age" : 45,
"street" : "Saint-Denis Street",
"city" : "Montreal"
}
如你所见,我们现在没有 address
对象,但它的两个字段(street
和 city
)被分配给文档的根级别。
使用 Compass 连接两个集合(MongoDB 的图形界面)
使用图形界面进行聚合很容易。我们只需要在 $lookup
聚合阶段执行以下步骤。
-
打开
MongoDBCompass
并连接到服务器。 -
如果需要,创建一个全新的数据库和两个集合。我们使用使用 Mongo shell 创建的相同数据库和集合。
-
打开你的集合,如下所示。
-
根据你的项目要求添加阶段;我们添加了
$lookup
聚合阶段。更新$lookup
字段并在右侧查看所需的结果。