MongoDB聚合Lookup:提取字段值存在于另一集合数组的文档
解决MongoDB聚合匹配「字段值存在于另一集合数组」的问题
你当前的聚合管道未建立menu.link与users.urls的关联匹配,因此无法筛选出符合条件的文档。以下是修正后的完整聚合方案及分步说明:
正确聚合管道(从users集合发起)
db.users.aggregate([ // 筛选目标用户,获取其urls数组 { '$match': { 'user': 'foo' } }, // 仅保留urls字段,减少后续数据处理量 { '$project': { 'urls': 1, '_id': 0 } }, // 关联menu集合,同时在子管道内完成匹配逻辑 { '$lookup': { 'from': 'menu', 'let': { user_urls: '$urls' }, // 将当前文档的urls数组传递给子管道 'pipeline': [ { '$match': { 'component': 'layout', // 核心判断:menu的link是否存在于用户的urls数组中 '$expr': { '$in': ['$link', '$$user_urls'] } } }, // 过滤出期望返回的字段 { '$project': { 'name': 1, 'link': 1, '_id': 0 } } ], 'as': 'matched_menus' } }, // 展开匹配结果数组 { '$unwind': '$matched_menus' }, // 将展开后的结果设为根文档,得到预期格式 { '$replaceRoot': { 'newRoot': '$matched_menus' } } ])
关键修正说明
- 在
$lookup中通过let参数传递当前用户的urls数组,子管道内用$$user_urls引用该变量 - 子管道的
$match阶段新增$expr+$in组合,实现「link存在于urls数组」的判断逻辑 - 通过
$unwind和$replaceRoot将数组格式的匹配结果转换为单文档输出
另一种高效写法(从menu集合发起)
如果想避免先筛选用户再关联的流程,也可以直接从menu集合发起聚合,效率可能更高:
db.menu.aggregate([ // 先筛选component为layout的menu文档 { '$match': { 'component': 'layout' } }, // 关联users集合,匹配目标用户的urls数组包含当前menu的link { '$lookup': { 'from': 'users', 'let': { menu_link: '$link' }, 'pipeline': [ { '$match': { 'user': 'foo', '$expr': { '$in': ['$$menu_link', '$urls'] } } } ], 'as': 'matched_users' } }, // 仅保留存在匹配用户的menu文档 { '$match': { 'matched_users': { '$ne': [] } } }, // 过滤出需要的字段 { '$project': { 'name': 1, 'link': 1, '_id': 0 } } ])
内容的提问来源于stack exchange,提问作者b81
相关产品推荐
相关产品推荐

