合并嵌套在数组 mongoose 中的对象内的 $lookup 值

Merge $lookup value inside objects nested in array mongoose

所以我有 2 个模型 userform

用户架构

firstName: {
  type: String,
  required: true,
},
lastName: {
  type: String,
  required: true,
},
email: {
  type: String,
  required: true,
}

表单架构

 approvalLog: [
      {
        attachments: {
          type: [String],
        },
        by: {
          type: ObjectId,
        },
        comment: {
          type: String,
        },
        date: {
          type: Date,
        },
      },
    ],
 userId: {
      type: ObjectId,
      required: true,
    },
... other form parameters

返回表单时,我试图将 approvalLog 中每个用户的用户信息汇总到各自的对象中,如下所示。

{
...other form info
 approvalLog: [
    {
      attachments: [],
      _id: '619cc4953de8413b548f61a6',
      by: '619cba9cd64af530448b6347',
      comment: 'visit store for disburement',
      date: '2021-11-23T10:38:13.565Z',
      user: {
        _id: '619cba9cd64af530448b6347',
        firstName: 'admin',
        lastName: 'user',
        email: 'admin@mail.com',
      },
    },
    {
      attachments: [],
      _id: '619cc4ec3ea3e940a42b2d01',
      by: '619cbd7b3de8413b548f61a0',
      comment: '',
      date: '2021-11-23T10:39:40.168Z',
      user: {
        _id: '619cbd7b3de8413b548f61a0',
        firstName: 'sam',
        lastName: 'ben',
        email: 'sb@mail.com',
      },
    },
    {
      attachments: [],
      _id: '61a9deab8f472c52d8bac095',
      by: '61a87fd93dac9b209096ed94',
      comment: '',
      date: '2021-12-03T09:08:59.479Z',
      user: {
        _id: '61a87fd93dac9b209096ed94',
        firstName: 'john',
        lastName: 'doe',
        email: 'jd@mail.com',
      },
    },
  ],
}

我当前的代码是

 Form.aggregate([
      {
      $lookup: {
        from: 'users',
        localField: 'approvalLog.by',
        foreignField: '_id',
        as: 'approvedBy',
      },
    },
    { $addFields: { 'approvalLog.user': { $arrayElemAt: ['$approvedBy', 0] } } },
 ])

但它只是 returns 所有对象的同一用户。如何为每个索引附加匹配的用户?

我也试过了

Form.aggregate([
      {
      $lookup: {
        from: 'users',
        localField: 'approvalLog.by',
        foreignField: '_id',
        as: 'approvedBy',
      },
    },
    {
      $addFields: {
        approvalLog: {
          $map: {
            input: { $zip: { inputs: ['$approvalLog', '$approvedBy'] } },
            in: { $mergeObjects: '$$this' },
          },
        },
      },
    },
 ])
  

这会将正确的用户添加到他们各自的对象中,但我只能将其添加到根对象中,而不能添加到新对象中。

你可以试试这个方法,

  • $map 迭代 approvalLog
  • 的循环
  • $filter 迭代 approvedBy 数组的循环并搜索用户 ID by
  • $arrayElemAt 从上面的过滤结果中获取第一个元素
  • $mergeObjects 合并 approvalLog 和筛选用户
  • 的当前对象属性
  • $$REMOVE现在不需要approvedBy
await Form.aggregate([
  {
    $lookup: {
      from: "users",
      localField: "approvalLog.by",
      foreignField: "_id",
      as: "approvedBy"
    }
  },
  {
    $addFields: {
      approvalLog: {
        $map: {
          input: "$approvalLog",
          as: "a",
          in: {
            $mergeObjects: [
              "$$a",
              {
                user: {
                  $arrayElemAt: [
                    {
                      $filter: {
                        input: "$approvedBy",
                        cond: { $eq: ["$$a.by", "$$this._id"] }
                      }
                    },
                    0
                  ]
                }
              }
            ]
          }
        }
      },
      approvedBy: "$$REMOVE"
    }
  }
])

Playground


第二种方法使用$unwind

  • $unwind解构approvalLog数组
  • $lookup 与用户合集
  • $addFields$arrayElemAt 从查找结果中获取第一个元素
  • $group by _id 并重建 approvalLog 数组并获取其他所需属性的第一个值
await Form.aggregate([
  { $unwind: "$approvalLog" },
  {
    $lookup: {
      from: "users",
      localField: "approvalLog.by",
      foreignField: "_id",
      as: "approvalLog.user"
    }
  },
  {
    $addFields: {
      "approvalLog.user": {
        $arrayElemAt: ["$approvalLog.user", 0]
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      approvalLog: { $push: "$approvalLog" },
      userId: { $first: "$userId" },
      // add your other properties like userId
    }
  }
])

Playground