Mongoose $lookup聚合如何过滤无关联子集合记录的查询结果
MongoDB $lookup 过滤无匹配子文档的父记录方案
核心逻辑:$lookup 关联后无匹配项时,as 指定的字段会返回空数组,只需要在$lookup阶段之后、分页阶段之前,新增一个$match阶段,筛除关联数组长度为0的文档即可。
注意事项
- 过滤阶段必须放在
$skip、$limit分页逻辑之前,否则分页计数会包含待丢弃的无效文档,可能出现返回结果条数少于设定limit值的问题 - 原代码分页顺序存在隐患:MongoDB聚合管道按阶段顺序执行,
$skip需要放在$limit之前,否则会先截取前N条再跳过,导致分页结果错乱,skip值大于0时问题会直接显现
调整后完整聚合代码
parentCollection.aggregate([ { '$match': { userId: '62810c69e880ed667073add1', type: 'data' } }, { '$lookup': { from: 'childCollection', let: { typeId: { '$toObjectId': '$typeId' } }, pipeline: [ { '$match': { '$expr': { '$eq': [ '$_id', '$$typeId' ] }, '$or': [ { 'field1': { '$regex': '737', '$options': 'i' } }, { 'field2': { '$regex': '737', '$options': 'i' } } ] } }], as: 'child' } }, // 新增阶段:过滤无任何匹配子记录的父文档 { '$match': { '$expr': { '$gt': [ { '$size': '$child' }, 0 ] } } }, // 修正分页顺序:先跳过指定条数,再截取页大小数量的结果 { '$skip': 0 }, { '$limit': 10 } ], {});
补充说明
如果业务需要把单条匹配的child数组展开为对象格式,可以在上述过滤阶段之后追加{ '$unwind': '$child' }阶段。由于提前过滤了空数组场景,不会触发$unwind默认丢弃空数组文档的隐式逻辑,整个聚合的执行逻辑更可控。
内容的提问来源于stack exchange,提问作者Althafu Rahman
相关产品推荐
相关产品推荐

