MongoDB聚合查询:关联双集合获取各办公地点对应的去重职位列表
错误原因
你原先的写法不符合$lookup的语法规范:标准$lookup不支持直接传入project/group配置,要实现关联阶段就处理员工数据、避免拉取全量员工文档的需求,需要使用MongoDB 3.6及以上版本支持的**带自定义pipeline的$lookup**语法。
最优实现方案
前置优化(必做,大幅提升查询效率)
给employees集合创建{office: 1, jobTitle: 1}联合索引,该索引可以直接覆盖关联查询、职位提取的全部需求,查询时不需要读取employees的完整文档,走索引即可返回所有需要的数据,性能提升非常明显。
正确聚合语句
db.offices.aggregate([ { $lookup: { from: "employees", localField: "_id", foreignField: "office", // 关联阶段直接在employees侧完成聚合,仅返回去重后的职位列表,大幅减少数据传输量 pipeline: [ // 仅保留需要的jobTitle字段,过滤无关数据 { $project: { jobTitle: 1, _id: 0 } }, // 按jobTitle分组实现去重 { $group: { _id: "$jobTitle" } }, // 将去重后的职位合并为单个数组 { $group: { _id: null, jobTitles: { $push: "$_id" } } }, // 仅保留职位数组字段 { $project: { jobTitles: 1, _id: 0 } } ], as: "tmpJobWrap" } }, // 格式化输出结构,无员工的办公点返回空职位数组 { $addFields: { jobTitles: { $ifNull: [ { $first: "$tmpJobWrap.jobTitles" }, [] ] } } }, // 移除临时字段,返回符合要求的结构 { $project: { tmpJobWrap: 0 } } ])
低版本MongoDB兼容方案(3.6以下版本使用,性能略差)
如果你的MongoDB版本不支持带pipeline的$lookup,可以用以下写法实现:
db.offices.aggregate([ { $lookup: { from: "employees", localField: "_id", foreignField: "office", as: "empList" } }, // 拉取所有员工后做职位去重 { $addFields: { jobTitles: { $reduce: { input: "$empList", initialValue: [], in: { $setUnion: [ "$$value", [ "$$this.jobTitle" ] ] } } } } }, // 移除临时字段 { $project: { empList: 0 } } ])
内容的提问来源于stack exchange,提问作者Leonard Niehaus
相关产品推荐
相关产品推荐

