文章发布地址:https://blog.qiuluo.xin/2019/03/16/mongo%E5%85%B3%E8%81%94%E5%86%85%E5%B5%8C%E6%95%B0%E7%BB%84%E5%AF%B9%E8%B1%A1/
我的需求是主表中的一个字段,关联另一个表内嵌数组中的对象。
简化一下表结构,如下所示
订单表中carId关联了用户的本田车
// orders
{
_id: ObjectId("5c861c98a352df5ea4739b0f"),
carId: ObjectId("5c7fc109cac1902780c6e4df")
}
// users
{
"_id" : ObjectId("5c88678ecb5fc635704d84bc"),
"carMessage" : [ // 汽车信息
{
"_id" : ObjectId("5c8b047e69e25054877d1da5"),
"brand" : "本田",
"series" : "CRV"
},
{
"_id" : ObjectId("5c8b049369e25054877d1da6"),
"brand" : "大众",
"series" : "探歌"
}
]
}
进行表关联
首先使用聚合函数以订单表为主表对人员表中的汽车进行关联
直接将users的carId和users的carMessage._id关联
db.getCollection("orders").aggregate([
{
$lookup:{
from: 'users',
localField: 'carId',
foreignField: 'carMessage._id',
as: "car"
}
}
])
结果如下:
/* 1 */
{
"_id" : ObjectId("5c8c96001936e8f1204a7dbe"),
"carId" : ObjectId("5c8b047e69e25054877d1da5"),
"car" : [
{
"_id" : ObjectId("5c8c96121936e8f1204a7dc7"),
"carMessage" : [
{
"_id" : ObjectId("5c8b047e69e25054877d1da5"),
"brand" : "本田",
"series" : "CRV"
},
{
"_id" : ObjectId("5c8b049369e25054877d1da6"),
"brand" : "大众",
"series" : "探歌"
}
]
}
]
}
结果查出了本田车所在的整条记录,显然不是我们想要的。
对文档结构重组
db.getCollection("orders").aggregate([
{
$lookup:{
from: 'users',
localField: 'carId',
foreignField: 'carMessage._id',
as: "car"
}
},
{
$unwind: {
path: "$car",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$car.carMessage",
preserveNullAndEmptyArrays: true
}
},
{
$project: {
'_id': 1,
'carId': 1,
'car': '$car.carMessage'
}
}
])
使用project进行重组展示。就得到了下面的结果。
/* 1 */
{
"_id" : ObjectId("5c8c96001936e8f1204a7dbe"),
"carId" : ObjectId("5c8b047e69e25054877d1da5"),
"car" : {
"_id" : ObjectId("5c8b047e69e25054877d1da5"),
"brand" : "本田",
"series" : "CRV"
}
}
/* 2 */
{
"_id" : ObjectId("5c8c96001936e8f1204a7dbe"),
"carId" : ObjectId("5c8b047e69e25054877d1da5"),
"car" : {
"_id" : ObjectId("5c8b049369e25054877d1da6"),
"brand" : "大众",
"series" : "探歌"
}
}
去掉了其它没用的字段,但是多出了本田车外的其它车信息。
去除多余文档
我们只需要得到其中carId和car._id相等的文档,就是想要的结果了,但是mongodb不像sql数据库可以直接查询两个字段相等的文档,所以我们只能使用其它方法来实现。
mongo虽然不能直接查询相等的文档结果,但是可以得到两字段是否相等的布尔值
首先在$project重组文档的时候加入一个flag,放入字段是否相等的结果
'flag': { "$eq": ["$carId", "$car.carMessage._id"] }
然后再加入一个查询条件来过滤掉不符合条件的文档
{
$match: {
'flag': true
}
}
最后再加上一个文档重组,得到想要的数据结构
{
$project: {
'carId': 0,
'flag': 0
}
}
最后我们需要执行的聚合函数就是下面这样的
db.getCollection("orders").aggregate([
{
$lookup:{
from: 'users',
localField: 'carId',
foreignField: 'carMessage._id',
as: "car"
}
},
{
$unwind: {
path: "$car",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$car.carMessage",
preserveNullAndEmptyArrays: true
}
},
{
$project: {
'_id': 1,
'carId': 1,
'car': '$car.carMessage',
'flag': {$eq: ["$carId", "$car.carMessage._id"]}
}
},
{
$match: {
'flag': true
}
},
{
$project: {
'carId': 0,
'flag': 0
}
}
])
这是最终得到的结果:
/* 1 */
{
"_id" : ObjectId("5c8c96001936e8f1204a7dbe"),
"car" : {
"_id" : ObjectId("5c8b047e69e25054877d1da5"),
"brand" : "本田",
"series" : "CRV"
}
}