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

MongoDB:如何聚合未知键的对象字段值为带键的数组集合?

MongoDB动态标签聚合:合并未知键为值数组

需求说明

有一批文档,每个文档的tags字段包含动态的键值对(键名无法提前确定),需要将所有文档聚合为一个,让每个标签键对应一个包含所有出现过的值的去重数组。

输入示例

{
    "_id" : ObjectId("6346826e3b4cd5a90b20b75b"),
    "tags" : {
        "planet" : "earth",
        "color" : "blue"
    }
}

{
    "_id" : ObjectId("634683723b4cd5a90b20b819"),
    "tags" : {
        "planet" : "earth",
        "color" : "green",
        "foo" : "bar"
    }
}

{
    "_id" : ObjectId("634683823b4cd5a90b20b829"),
    "tags" : {
        "foo" : "acme",
        "color" : "red",
        "xyz" : "1"
    }
}

预期输出

{
    "_id" : ObjectId("634684063b4cd5a90b20b87f"),
    "tags" : {
        "planet" : [ "earth" ],
        "color" : [ "blue", "green", "red" ],
        "foo" : [ "bar", "acme" ],
        "xyz" : [ "1" ]
    }
}

解决方案

使用MongoDB聚合框架,通过以下管道实现:

db.collection.aggregate([
    // 1. 把tags对象转成键值对数组,处理动态键
    {
        $project: {
            tagPairs: { $objectToArray: "$tags" }
        }
    },
    // 2. 展开每个键值对,让单个标签键值对独立成文档
    {
        $unwind: "$tagPairs"
    },
    // 3. 按标签键分组,收集并去重对应的值
    {
        $group: {
            _id: "$tagPairs.k",
            values: { $addToSet: "$tagPairs.v" }
        }
    },
    // 4. 把所有标签的键值对聚合到一个数组中
    {
        $group: {
            _id: null,
            tags: { $push: { k: "$_id", v: "$values" } }
        }
    },
    // 5. 把数组转回对象,同时设置自定义_id
    {
        $project: {
            _id: ObjectId("634684063b4cd5a90b20b87f"),
            tags: { $arrayToObject: "$tags" }
        }
    }
])

步骤解释

  • $project + $objectToArray:将tags对象转换为[{k: "键名", v: "值"}, ...]的数组结构,解决动态键无法直接处理的问题。
  • $unwind:拆分数组,让每个标签键值对单独成为一个文档,方便后续分组操作。
  • $group(第一次):按标签键分组,用$addToSet自动去重并收集所有对应的值。
  • $group(第二次):将所有标签的分组结果合并成一个数组,为转回对象做准备。
  • $project + $arrayToObject:把数组重新转换为tags对象,同时设置预期的_id(若不需要固定_id,可改为null或直接省略该字段)。

内容的提问来源于stack exchange,提问作者Bernd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:20:27