不执行$unwind时能否对前序$lookup返回结果执行二次关联查询
解决方案
完全可以不使用$unwind实现二次关联,通过嵌套$lookup的写法就能保留原有projects数组结构,实现你要的输出效果。
注意:该写法需要MongoDB 3.6及以上版本支持,这也是目前主流生产环境的最低版本要求
现有集合结构
// Client集合 Client { _id, companyId // 初始匹配字段 } // Project集合 Project { _id, clientId, // 第一阶段lookup关联字段(对应client._id) createdBy } // User集合 User { _id, // 第二阶段lookup关联字段(对应project.createdBy) firstName, lastName }
原有聚合代码
Client.aggregate([ { $match: { companyId: mongoose.Types.ObjectId(req.user.companyId) } }, { $lookup: { from: 'projects', localField: '_id', foreignField: 'clientId', as: 'projects' } }, ]) .sort({ createdAt: -1 })
修改后的完整聚合代码
Client.aggregate([ { $match: { companyId: mongoose.Types.ObjectId(req.user.companyId) } }, { $lookup: { from: 'projects', localField: '_id', foreignField: 'clientId', as: 'projects', // 嵌套pipeline处理每个project的关联查询 pipeline: [ { $lookup: { from: 'users', localField: 'createdBy', foreignField: '_id', as: 'createdBy' } }, // 把createdBy从单元素数组转成对象 { $addFields: { createdBy: { $first: '$createdBy' } } }, // 可选:只保留需要的字段,不需要可以删除该阶段 { $project: { _id: 1, 'createdBy.firstName': 1, 'createdBy.lastName': 1 // 其他需要保留的project字段自行补充 } } ] } } ]) .sort({ createdAt: -1 })
实现逻辑说明
- 外层
$lookup保持原有逻辑关联projects集合,生成projects数组 - 通过给
$lookup加pipeline参数,在查询每个project的同时直接执行第二层$lookup,关联users集合获取对应用户信息 - 用
$addFields配合$first把createdBy从默认的数组格式转成对象,符合输出要求 - 全程不需要对projects数组执行
$unwind,输出结构和期望的完全一致。
内容的提问来源于stack exchange,提问作者Ryne
相关产品推荐
相关产品推荐

