Mongoose如何查询findOne中populate关联结果为null的文档
实现方案
Mongoose 支持两种常用方式实现该需求,分别适配不同数据量场景:
方案1:populate + 内存过滤(小数据量场景)
你原有 populate 逻辑不需要修改,Mongoose 在 populate 时如果 match 条件不匹配,会自动将对应关联字段设为 null,查询完成后直接过滤即可:
const allEntries = await Entry.find({}).populate({ path: 'myref', match: ref => ({ date: { $gte: new Date(ref.timestamp).setHours(0, 0, 0, 0), $lt: new Date(ref.timestamp).setHours(23, 59, 59, 9999) } }) }) // 筛选populate返回null的文档 const targetEntries = allEntries.filter(item => !item.myref)
该方案写法最简单,适合 Entry 集合数据量不大的场景。
方案2:聚合管道(大数据量高性能场景)
如果数据量较大,内存过滤会浪费性能,可以直接用 MongoDB 聚合管道的 $lookup 实现完全等价的逻辑,直接在数据库层面完成过滤:
const targetEntries = await Entry.aggregate([ { $lookup: { from: 'myrefs', // 替换为myref对应模型在MongoDB中的实际集合名,一般为模型名的复数小写形式 let: { parentTimestamp: '$timestamp', parentRefId: '$myref' }, pipeline: [ { $match: { $expr: { $and: [ // 等价populate的关联ID匹配逻辑 { $eq: ['$_id', '$$parentRefId'] }, // 等价原有的日期匹配规则 { $gte: ['$date', { $dateFromString: { dateString: { $dateToString: { date: new Date('$$parentTimestamp'), format: '%Y-%m-%d' } } } }] }, { $lt: ['$date', { $add: [{ $dateFromString: { dateString: { $dateToString: { date: new Date('$$parentTimestamp'), format: '%Y-%m-%d' } } } }, 86399999] }] } ] } } } ], as: 'myref' } }, // 把lookup返回的数组转成单个对象,和populate默认行为对齐 { $unwind: { path: '$myref', preserveNullAndEmptyArrays: true } }, // 直接在数据库层过滤关联结果为null的文档 { $match: { myref: null } } ]) // 可选:如果需要恢复Mongoose文档实例的内置方法,可以调用hydrate targetEntries.forEach(item => Entry.hydrate(item))
内容的提问来源于stack exchange,提问作者nrgyzer
相关产品推荐
相关产品推荐

