MongoDB聚合:如何将lookup结果存入嵌套数组?
MongoDB聚合:将嵌套数组中的参与者ID替换为关联对象
我需要把文档中schedules数组里每个schedule的participants(ID数组)替换为从customers集合查询到的用户对象,最终得到如下格式的结果:
{ "name": "EXAMPLE", "schedules": [ { "schedule_id": "id1", "participants": [ { "_id": "participant_id1", "name": "name1" }, { "_id": "participant_id2", "name": "name2" } ] }, { "schedule_id": "id2", "participants": [ { "_id": "participant_id1", "name": "name1" }, { "_id": "participant_id2", "name": "name2" } ] }, { "schedule_id": "id3", "participants": [ { "_id": "participant_id1", "name": "name1" } ] } ] }
原有的聚合管道存在逻辑问题:分组时用$first只能拿到单个schedule和参与者,无法将同一schedule下的多个参与者重新聚合回数组,达不到预期效果。以下是修正后的两种实现方案:
方案一:MongoDB 3.6+ 版本(推荐)
利用3.6+版本支持的数组字段直接关联特性,无需多次展开数组,简化流程:
[ // 展开schedules数组,单独处理每个schedule条目 { $unwind: { path: "$schedules", preserveNullAndEmptyArrays: true } }, // 直接用schedule的participants数组关联customers集合,返回匹配的用户对象数组 { $lookup: { from: "customers", localField: "schedules.participants", foreignField: "_id", as: "schedules.participant_details" } }, // 过滤掉参与者对象中不需要的字段(如address、birthday) { $project: { name: 1, "schedules.schedule_id": 1, "schedules.participant_details._id": 1, "schedules.participant_details.name": 1 } }, // 把临时字段重命名为participants,覆盖原ID数组,并删除临时字段 { $addFields: { "schedules.participants": "$schedules.participant_details", "schedules.participant_details": "$$REMOVE" } }, // 重新分组,将单个schedule条目聚合回数组,恢复原文档结构 { $group: { _id: "$_id", name: { $first: "$name" }, schedules: { $push: "$schedules" } } } ]
步骤说明
- 展开schedules数组:将嵌套的
schedules拆分为单个文档,方便单独处理每个schedule的参与者关联。 - 关联customers集合:直接用当前schedule的
participants(ID数组)匹配customers的_id,返回的用户对象存入临时字段,省去提前展开participants的步骤。 - 过滤冗余字段:只保留需要的字段,移除不必要的参与者属性。
- 重命名字段:替换掉原有的ID数组,恢复schedule的预期结构。
- 重新聚合文档:按原文档ID分组,用
$push将处理后的schedule条目重新组合成数组。
方案二:兼容MongoDB 3.6以下版本
如果你的MongoDB版本不支持数组字段关联,需要通过两次分组来聚合参与者数组:
[ { $unwind: { path: "$schedules", preserveNullAndEmptyArrays: true } }, // 展开每个schedule的participants数组,单个条目对应一个参与者ID { $unwind: { path: "$schedules.participants", preserveNullAndEmptyArrays: true } }, // 关联单个参与者对象 { $lookup: { from: "customers", localField: "schedules.participants", foreignField: "_id", as: "participant" } }, { $unwind: { path: "$participant", preserveNullAndEmptyArrays: true } }, // 过滤冗余字段 { $project: { name: 1, "schedules.schedule_id": 1, "participant._id": 1, "participant.name": 1 } }, // 第一次分组:按文档ID+schedule_id聚合,把同一schedule的参与者组合成数组 { $group: { _id: { _id: "$_id", schedule_id: "$schedules.schedule_id" }, name: { $first: "$name" }, participants: { $push: "$participant" } } }, // 第二次分组:按文档ID聚合,把schedule条目组合成数组 { $group: { _id: "$_id._id", name: { $first: "$name" }, schedules: { $push: { schedule_id: "$_id.schedule_id", participants: "$participants" } } } } ]
内容的提问来源于stack exchange,提问作者Jimmy Nelle
相关产品推荐
相关产品推荐

