如何将$lookup用于嵌套数组作为localField(MongoDB聚合)
MongoDB聚合:嵌套数组的$lookup替换(避免$unwind)
集合结构
Countries集合
[ { "country": "UK", "shops": [ {"city": "London", "fruits": [1, 2]}, {"city": "Birmingham", "fruits": [2]} ] }, { "country": "DE", "shops": [ {"city": "Munich", "fruits": [2, 3]}, {"city": "Berlin", "fruits": [1, 2, 3]} ] } ]
Fruits集合
[ { "uid": 1, "name": "banana" }, { "uid": 2, "name": "kiwi" }, { "uid": 3, "name": "mango" } ]
需求目标
使用MongoDB聚合框架,将Countries集合中shops.fruits的UID列表替换为Fruits集合中对应uid的完整文档(注意:Fruits的uid是自定义字段,与MongoDB原生_id无关)。
尝试的管道及问题
尝试的聚合管道:
pipeline = [ { "$match": {}, }, { "$lookup": { "from": "fruits", "localField": "shops.fruits", "foreignField": "uid", "as": "shops.fruits", }, }, ];
问题:该管道会将shops数组转为单个对象,仅保留第一个shop的信息并替换其fruits字段,而非遍历整个shops数组完成替换。
实际错误结果:
[ { "country": "UK", "shops": { "city": "London", "fruits": [ {"uid": 1, "name": "banana"}, {"uid": 2, "name": "kiwi"} ] } } // ... 其他国家数据同理 ]
解决方案(无需$unwind)
核心思路:先一次性拉取所有Fruits文档到临时字段,再通过数组操作符遍历嵌套数组完成匹配替换,避免使用$unwind破坏原数组结构。
完整聚合管道:
pipeline = [ // 拉取所有Fruits文档到临时字段allFruits { "$lookup": { "from": "fruits", "localField": "", // 空字段表示匹配所有文档 "foreignField": "", "as": "allFruits" } }, // 遍历shops数组,替换每个shop的fruits字段 { "$project": { "country": 1, "shops": { "$map": { "input": "$shops", "as": "shop", "in": { "city": "$$shop.city", "fruits": { "$map": { "input": "$$shop.fruits", "as": "fruitUid", "in": { "$first": { "$filter": { "input": "$allFruits", "cond": {"$eq": ["$$this.uid", "$$fruitUid"]} } } } } } } } }, "allFruits": 0 // 移除临时字段 } } ]
代码解释
- $lookup阶段:通过空的
localField和foreignField拉取Fruits集合的所有文档,存储到allFruits临时字段,避免多次关联查询。 - $project阶段:
- 使用
$map遍历shops数组,保留每个shop的city字段; - 对每个shop的
fruitsUID列表,再次用$map遍历每个UID,通过$filter从allFruits中匹配对应uid的文档,$first确保只取匹配到的单个文档(因为UID唯一); - 最后移除临时字段
allFruits,保持结果结构整洁。
- 使用
期望结果
[ { "country": "UK", "shops": [ { "city": "London", "fruits": [ {"uid": 1, "name": "banana"}, {"uid": 2, "name": "kiwi"} ] }, { "city": "Birmingham", "fruits": [{"uid": 2, "name": "kiwi"}] } ] }, { "country": "DE", "shops": [ { "city": "Munich", "fruits": [ {"uid": 2, "name": "kiwi"}, {"uid": 3, "name": "mango"} ] }, { "city": "Berlin", "fruits": [ {"uid": 1, "name": "banana"}, {"uid": 2, "name": "kiwi"}, {"uid": 3, "name": "mango"} ] } ] } ]
内容的提问来源于stack exchange,提问作者Lucien Chardon
相关产品推荐
相关产品推荐

