如何执行MongoDB lookup并合并多集合关联结果为单一数据集
MongoDB多集合关联按好友维度合并解决方案
你之前尝试用$unionWith不符合需求,这个操作符是用来合并多个集合的同结构文档,不适合做跨集合的维度关联。你遇到的_id和userId字段差异的问题,通过在匹配阶段指定对应字段做等值关联即可解决,完整的聚合查询如下:
db.users.aggregate([ // 匹配目标用户a { $match: { _id: "a" } }, // 关联查询a的好友关系列表 { $lookup: { from: "friends", localField: "_id", foreignField: "userId", as: "a_myfriends" } }, // 关联查询所有好友的邮箱信息 { $lookup: { from: "users", localField: "a_myfriends.otherUserId", foreignField: "_id", as: "emailaddr" } }, // 关联查询所有好友的发件数量,自动过滤a本人的记录 { $lookup: { from: "emailsSent", localField: "a_myfriends.otherUserId", foreignField: "userId", as: "emailsent" } }, // 按好友维度合并三个数组的信息 { $project: { _id: 1, a_myfriends: { $map: { input: "$a_myfriends", as: "friend", in: { otherUserId: "$$friend.otherUserId", email: { $getField: { input: { $first: { $filter: { input: "$emailaddr", cond: { $eq: ["$$this._id", "$$friend.otherUserId"] } } } }, field: "email" } }, number: { $getField: { input: { $first: { $filter: { input: "$emailsent", cond: { $eq: ["$$this.userId", "$$friend.otherUserId"] } } } }, field: "number" } } } } } } }, // 清理无发件记录好友的null字段,匹配预期输出 { $addFields: { a_myfriends: { $map: { input: "$a_myfriends", as: "item", in: { $arrayToObject: { $filter: { input: { $objectToArray: "$$item" }, cond: { $ne: ["$$this.v", null] } } } } } } } } ])
核心逻辑说明
- 前4个阶段是你当前已有的查询逻辑,核心改动在后续的数组合并处理阶段
- 通过
$map遍历每一条好友关系,对单个好友分别匹配邮箱数组和发件数数组的对应记录:- 邮箱匹配:用
$filter筛选users集合返回的数组中_id等于好友otherUserId的记录,取出邮箱字段 - 发件数匹配:用
$filter筛选emailsSent集合返回的数组中userId等于好友otherUserId的记录,取出发件数字段
- 邮箱匹配:用
- 最后清理阶段会自动删除无发件记录的好友的
number字段,输出和你要求完全一致的结构
内容的提问来源于stack exchange,提问作者MrLister
相关产品推荐
相关产品推荐

