You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将$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 // 移除临时字段
        }
    }
]

代码解释

  1. $lookup阶段:通过空的localField和foreignField拉取Fruits集合的所有文档,存储到allFruits临时字段,避免多次关联查询。
  2. $project阶段:
    • 使用$map遍历shops数组,保留每个shop的city字段;
    • 对每个shop的fruits UID列表,再次用$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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 07:59:53