具有 3 个级别的 MongoDB 嵌套查找
Posted
技术标签:
【中文标题】具有 3 个级别的 MongoDB 嵌套查找【英文标题】:MongoDB nested lookup with 3 levels 【发布时间】:2016-07-01 09:22:24 【问题描述】:我需要从数据库中检索整个单个对象层次结构作为 JSON。实际上,将高度赞赏有关实现此结果的任何其他解决方案的建议。我决定使用带有 $lookup
支持的 MongoDB。
所以我有三个集合:
派对
"_id" : "2", "name" : "party2"
"_id" : "5", "name" : "party5"
"_id" : "4", "name" : "party4"
"_id" : "1", "name" : "party1"
"_id" : "3", "name" : "party3"
地址
"_id" : "a3", "street" : "Address3", "party_id" : "2"
"_id" : "a6", "street" : "Address6", "party_id" : "5"
"_id" : "a1", "street" : "Address1", "party_id" : "1"
"_id" : "a5", "street" : "Address5", "party_id" : "5"
"_id" : "a2", "street" : "Address2", "party_id" : "1"
"_id" : "a4", "street" : "Address4", "party_id" : "3"
地址评论
"_id" : "ac2", "address_id" : "a1", "comment" : "Comment2"
"_id" : "ac1", "address_id" : "a1", "comment" : "Comment1"
"_id" : "ac5", "address_id" : "a5", "comment" : "Comment6"
"_id" : "ac4", "address_id" : "a3", "comment" : "Comment4"
"_id" : "ac3", "address_id" : "a2", "comment" : "Comment3"
我需要检索所有具有所有相应地址的各方,并将地址 cmet 作为记录的一部分。我的聚合:
db.party.aggregate([
$lookup:
from: "address",
localField: "_id",
foreignField: "party_id",
as: "address"
,
$unwind: "$address"
,
$lookup:
from: "addressComment",
localField: "address._id",
foreignField: "address_id",
as: "address.addressComment"
])
结果很奇怪。有些记录没问题。但是缺少_id: 4
的派对(没有地址)。另外,结果集中有两个Party_id: 1
(但地址不同):
"_id": "1",
"name": "party1",
"address":
"_id": "2",
"street": "Address2",
"party_id": "1",
"addressComment": [
"_id": "3",
"address_id": "2",
"comment": "Comment3"
]
"_id": "1",
"name": "party1",
"address":
"_id": "1",
"street": "Address1",
"party_id": "1",
"addressComment": [
"_id": "1",
"address_id": "1",
"comment": "Comment1"
,
"_id": "2",
"address_id": "1",
"comment": "Comment2"
]
"_id": "3",
"name": "party3",
"address":
"_id": "4",
"street": "Address4",
"party_id": "3",
"addressComment": []
"_id": "5",
"name": "party5",
"address":
"_id": "5",
"street": "Address5",
"party_id": "5",
"addressComment": [
"_id": "5",
"address_id": "5",
"comment": "Comment5"
]
"_id": "2",
"name": "party2",
"address":
"_id": "3",
"street": "Address3",
"party_id": "2",
"addressComment": [
"_id": "4",
"address_id": "3",
"comment": "Comment4"
]
请帮我解决这个问题。我对 MongoDB 还很陌生,但我觉得它可以满足我的需求。
【问题讨论】:
【参考方案1】:“麻烦”的原因是第二个聚合阶段 - $unwind: "$address"
。它删除了_id: 4
的记录(因为它的地址数组是空的,正如你提到的)并为_id: 1
和_id: 5
的当事人生成两条记录(因为他们每个人都有两个地址)。
为防止删除没有地址的各方,您应将$unwind
阶段的preserveNullAndEmptyArrays
选项设置为true
。
为了防止各方重复其不同的地址,您应该将$group
聚合阶段添加到您的管道。另外,使用$project
阶段和$filter
运算符来排除输出中的空地址记录。
db.party.aggregate([
$lookup:
from: "address",
localField: "_id",
foreignField: "party_id",
as: "address"
,
$unwind:
path: "$address",
preserveNullAndEmptyArrays: true
,
$lookup:
from: "addressComment",
localField: "address._id",
foreignField: "address_id",
as: "address.addressComment",
,
$group:
_id : "$_id",
name: $first: "$name" ,
address: $push: "$address"
,
$project:
_id: 1,
name: 1,
address:
$filter: input: "$address", as: "a", cond: $ifNull: ["$$a._id", false]
]);
【讨论】:
坦克你鲥鱼!但是记录 4 有一个小问题: "_id": "4", "name": "party4", "address": [ "addressComment": [] ]
如您所见 - 地址应该为空,但它是一个空记录...如果地址注释为空,我们可以跳过地址吗?在其他情况下,此地址将被视为记录。
实际上,根据 $unwind 操作的新“preserveNullAndEmptyArrays”字段的描述(自 3.2 起),我看到提供的解决方案按预期工作。现在我们可以跳过“$project”这一步并指定这个“$unwind”而不是简单的一个:$unwind: path: "$address",preserveNullAndEmptyArrays: true
。我会接受你的回答,感谢你快速而清晰的回复!
@Shad 我有非常相似的问题。这里 OP 的代码在party
集合中只有一个名为name
的属性,因此您使用$first
在$group
中获取它。假设我有 10 多个属性,那么有什么方法可以自动获取所有属性而不单独提及每个属性?
如果同一地址 id 有不同的 cmets,我们如何为“addressComment”添加组子句?如前所述,此查询适用于“地址”级别的分组。【参考方案2】:
使用 mongodb 3.6 及以上$lookup
语法,无需使用$unwind
即可连接嵌套字段非常简单。
db.party.aggregate([
"$lookup":
"from": "address",
"let": "partyId": "$_id" ,
"pipeline": [
"$match": "$expr": "$eq": ["$party_id", "$$partyId"] ,
"$lookup":
"from": "addressComment",
"let": "addressId": "$_id" ,
"pipeline": [
"$match": "$expr": "$eq": ["$address_id", "$$addressId"]
],
"as": "address"
],
"as": "address"
,
"$unwind": "$address"
])
【讨论】:
如果需要,您将如何访问内部管道中的 partyId? @Paulo 使用$$
符号
你确定吗,我知道你可以像这样得到addressId $$addressId
@Paulo 请参考this link in the mongo docs 了解清楚
嗨@Ashh,你能在***.com/questions/70021771/…查看我的问题以上是关于具有 3 个级别的 MongoDB 嵌套查找的主要内容,如果未能解决你的问题,请参考以下文章