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

MongoDB聚合Lookup填充嵌套数组added_by字段的问题

问题

需要将claim文档中actions数组里的added_by字段从ObjectId替换为对应的用户文档,同时保留原action的其他字段(比如message)。

示例结构

原claim文档结构:

{
    _id: ObjectId('.....'),
    actions: [
        {
            added_by: ObjectId('64d4f8a3fd3df..'),
            message: 'test'
        },
        {
            added_by: ObjectId('64d4f8a3fd3....'),
            message: 'test2'
        },
        // 其余记录
    ]
}

期望效果:

{
    _id: ObjectId('.....'),
    actions: [
        {
            added_by: {
                "email": "test@gmail.com",
                // 其余属性
            },
            message: 'test'
        },
        {
            added_by: {
                "email": "testf@gmail.com",
                // 其余属性
            },
            message: 'test2'
        },
        // 其余记录
    ]
}

尝试的代码及问题

尝试了以下聚合Lookup代码:

lookup.push({
    $lookup: {
        from: 'users', // 关联的users集合
        let: { actions: '$actions' }, // 定义匹配变量
        as: 'actions', // 存储结果的字段
        pipeline: [
            {
                $match: {
                    $expr: {
                        $in: ['$_id', '$$actions.added_by'], // 匹配_id在added_by数组中的用户
                    },
                },
            }
        ],
    },
});

但遇到两个问题:

  • 操作会覆盖整个actions数组,导致原有的message等字段丢失;
  • 若多个action由同一用户创建,输出中仅显示一次该用户,而非对应每个action都显示。

完整示例文档

claim文档:

{
    _id: ObjectId('64d79a9b5239b08bb7c00bb0'),
    claim_message: 'hola',
    files: [],
    added_by: ObjectId('64d4f8a3fd3dfa4fd2a37607'),
    company: ObjectId('64d4b30dfd3dfa4fd2a37283'),
    services: [
        ObjectId('64d4b0f4fd3dfa4fd2a3720f')
    ],
    status: 'open',
    createdAt: ISODate('2023-08-12T14:43:39.343Z'),
    updatedAt: ISODate('2023-08-12T18:57:40.162Z'),
    actions: [
        {
            files: null,
            added_by: ObjectId('64d4f8a3fd3dfa4fd2a37607'),
            message: 'testing'
        },
        {
            files: null,
            added_by: ObjectId('64d4f8a3fd3dfa4fd2a37607'),
            message: 'new reply'
        },
        {
            files: null,
            added_by: ObjectId('64d4f8a3fd3dfa4fd2a37879'),
            message: 'another reply'
        }
    ]
}

user集合文档:

[
    {
        _id: ObjectId('64d4f8a3fd3dfa4fd2a37607'),
        account_type: 'CLIENT',
        email: 'linked@gmail.com'
    },
    {
        _id: ObjectId('64d4f8a3fd3dfa4fd2a37879'),
        account_type: 'CLIENT',
        email: 'visitor@gmail.com'
    }
]

解决方案

要解决这两个问题,需要先拆分actions数组,关联用户后再重组结构,同时保留所有原字段。具体聚合管道如下:

db.claims.aggregate([
    // 1. 将actions数组拆分为独立文档,保留原claim的其他字段
    { $unwind: "$actions" },
    // 2. 关联users集合,匹配每个action的added_by对应的用户
    {
        $lookup: {
            from: "users",
            localField: "actions.added_by",
            foreignField: "_id",
            as: "actions.added_by"
        }
    },
    // 3. 将关联得到的用户数组转为单个对象(每个action仅对应一个用户)
    { $set: { "actions.added_by": { $first: "$actions.added_by" } } },
    // 4. 按claim的_id重新分组,重组actions数组并保留其他字段
    {
        $group: {
            _id: "$_id",
            claim_message: { $first: "$claim_message" },
            files: { $first: "$files" },
            added_by: { $first: "$added_by" },
            company: { $first: "$company" },
            services: { $first: "$services" },
            status: { $first: "$status" },
            createdAt: { $first: "$createdAt" },
            updatedAt: { $first: "$updatedAt" },
            actions: { $push: "$actions" }
        }
    }
])

代码说明

  1. $unwind阶段:拆分actions数组为单个文档,确保每个action都能单独关联用户,避免同一用户只显示一次的问题。
  2. $lookup阶段:用每个action的added_by字段匹配users集合的_id,将匹配到的用户存入actions.added_by(此时为数组)。
  3. $set阶段:利用$first将用户数组转为单个对象,替换原有的ObjectId。
  4. $group阶段:按claim的_id重新分组,将拆分的action重新组合为数组,同时完整保留原claim的所有其他字段。

处理后,既能保留原action的所有字段(如message、files),又能让每个action正确关联到对应用户文档,同一用户创建的多个action也会一一对应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:33:16