Mongoose如何根据关联ref集合字段值过滤主集合文档
核心原因说明
你之前用populate的match参数无效是因为Mongoose的populate是先查询主集合(booking)的全部符合基础条件的文档,再去关联查询从集合填充字段,所以match只能过滤填充的内容,没法反向过滤主集合的文档。
解决方案1:分两次查询(实现最简单,性能更优)
先分别根据名称查询拿到对应州、城市的ObjectId,再用Id作为过滤条件查booking集合,代码示例:
// 1. 先查符合条件的州Id const targetState = await State.findOne({ name: '目标州名' }).select('_id').lean() if (!targetState) return [] // 没有匹配的州直接返回空 // 2. 再查符合条件的城市Id const targetCity = await City.findOne({ name: '目标城市名' }).select('_id').lean() if (!targetCity) return [] // 没有匹配的城市直接返回空 // 3. 用两个Id过滤booking,只返回id和service字段 const result = await Booking.find({ state: targetState._id, city: targetCity._id }).select('id service -_id') // 加-_id是为了去掉默认返回的_id,不需要可以删掉
解决方案2:聚合查询一次性实现(单请求完成,适合复杂关联场景)
用MongoDB的聚合管道$lookup实现类似SQL的联表查询逻辑,代码示例:
const result = await Booking.aggregate([ // 关联州集合 { $lookup: { from: 'states', // State集合在MongoDB里的实际集合名,一般为小写复数 localField: 'state', foreignField: '_id', as: 'stateInfo' } }, // 关联城市集合 { $lookup: { from: 'cities', // City集合在MongoDB里的实际集合名 localField: 'city', foreignField: '_id', as: 'cityInfo' } }, // 过滤符合州名、城市名的文档 { $match: { 'stateInfo.name': '目标州名', 'cityInfo.name': '目标城市名' } }, // 只返回需要的id和service字段 { $project: { id: 1, service: 1, _id: 0 // 不需要返回_id可以保留这个配置 } } ])
优先推荐方案1:州和城市的名称一般是唯一值,两次简单单集合查询对索引的利用率更高,性能优于联表聚合,代码也更易调试。
内容的提问来源于stack exchange,提问作者Sumit Soni
相关产品推荐
相关产品推荐

