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

MongoDB聚合:将一个$lookup结果合并到另一lookup的data数组子项

问题根源

原有聚合逻辑存在两处核心错误:

  1. 第二个$lookup关联字段写死为不存在的items.activity_type_id,第一次关联activities集合后,查询结果实际存放在data数组中,无items字段
  2. 关联applications的时机错误:在data还是数组结构时直接做顶层关联,查询到的activity_type自然会挂在文档顶层,无法对应到data内的单条activity记录
修正后的聚合代码
const results = await Constants.aggregate([
    {
        $match: query,
    },
    {
        $unwind: {
            path: '$value.categories',
            preserveNullAndEmptyArrays: true,
        },
    },
    {
        $lookup: {
            from: 'activity',
            localField: 'value.categories.id',
            foreignField: 'config.agenda_item_category_ids',
            as: 'data',
        },
    },
    // 拆分data数组,每条文档对应单个activity记录
    {
        $unwind: {
            path: '$data',
            preserveNullAndEmptyArrays: true,
        }
    },
    // 基于单条activity的activity_type_id关联applications,结果直接写入data子字段
    {
        $lookup: {
            from: 'applications',
            localField: 'data.activity_type_id',
            foreignField: '_id',
            as: 'data.activity_type',
        },
    },
    {
        $addFields: {
            // lookup默认返回数组,1:1关联场景下直接取第一个元素转为对象结构
            'data.activity_type': { $arrayElemAt: ['$data.activity_type', 0] }
        }
    },
    // 按分类维度分组,把拆分后的activity重新组装为data数组
    {
        $group: {
            _id: '$value.categories.id',
            title: { $first: '$value.categories.title' },
            description: { $first: '$value.categories.description' },
            icon_src: { $first: '$value.categories.icon_src' },
            category_id: { $first: '$value.categories.id' },
            data: { $push: '$data' }
        }
    },
    {
        $project: {
            _id: 0,
            category_id: 1,
            title: 1,
            description: 1,
            icon_src: 1,
            data: 1
        }
    }
]);
输出结构说明

修正后返回结果完全匹配预期结构,每个activity对应的activity_type会直接嵌入data数组的对应子项中:

[
    {
        "category_id": "001",
        "title": "test 1",
        "data": [
            {
                "propert1": "",
                "propert2": "",
                "config": {
                    "agenda_item_category_ids": ["001", "002"]
                },
                "activity_type_id": "123",
                "activity_type": {
                    "_id": "123",
                    "prop1": "",
                    "prop2": ""
                }
            }
        ]
    },
    {
        "category_id": "002",
        "title": "test 2",
        "data": [
            {
                "propert1": "",
                "propert2": "",
                "config": {
                    "agenda_item_category_ids": ["001", "002"]
                },
                "activity_type_id": "123",
                "activity_type": {
                    "_id": "123",
                    "prop1": "",
                    "prop2": ""
                }
            },
            {
                "propert1": "",
                "propert2": "",
                "config": {
                    "agenda_item_category_ids": ["002"]
                },
                "activity_type_id": "456",
                "activity_type": {
                    "_id": "456",
                    "prop1": "",
                    "prop2": ""
                }
            }
        ]
    }
]
关键改动点
  • 关联applications集合前先通过$unwind拆开data数组,保证单条文档只对应一个activity,避免关联结果错位
  • 第二个$lookup直接将关联结果写入data.activity_type路径,不需要额外做顶层字段的映射转换
  • 关联完成后用$arrayElemAt把lookup返回的数组转为单个对象,符合activity和application 1:1关联的业务逻辑
  • 最后通过$group把同分类下的activity重新聚合成data数组,结构和预期完全一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:36:38