如何在Mongoose的populate()后使用.where().equal()方法?
如何根据关联的Commerce名称查询Offer
嘿,我发现你现在的写法存在一个关键问题:mongoose的.populate()是在初始的Offer查询完成之后才执行的,所以你不能直接在Offre.find()的链式调用里用.where('commerce.name')来过滤——因为这时候commerce字段还只是存储的ObjectId,不是完整的Commerce文档,这种过滤根本不会生效。
下面给你三种可行的解决方案,你可以根据自己的场景选择:
方案1:先查匹配的Commerce,再查关联Offer(最直观)
这是最容易理解和维护的方式,分两步走:
module.exports.getOffresByName = function(req, callback) { const name = req; // 先找到名称为'Haircut'的Commerce Commerce.findOne({ name: name }) .then(targetCommerce => { if (!targetCommerce) { return callback(null, []); // 没找到对应的Commerce就返回空数组 } // 用找到的Commerce的ID查询所有关联的Offer Offre.find({ commerce: targetCommerce._id }) .populate('commerce') // 可选:如果需要返回完整的Commerce信息 .exec(callback); }) .catch(err => callback(err)); };
如果给Commerce.name和Offre.commerce字段加上索引,这个方案的性能会非常好。
方案2:用聚合管道一次完成查询
如果想一步到位,可以用MongoDB的聚合管道来关联集合并过滤:
module.exports.getOffresByName = function(req, callback) { const name = req; Offre.aggregate([ // 关联Commerce集合,把匹配的Commerce数据附加到Offer文档中 { $lookup: { from: 'commerces', // 注意这里是MongoDB中Commerce集合的实际名称(通常是小写复数形式) localField: 'commerce', foreignField: '_id', as: 'commerce' } }, // 过滤出Commerce名称匹配的Offer { $match: { 'commerce.name': { $eq: name } } }, // 可选:把commerce数组转为单个对象(因为一个Offer只关联一个Commerce) { $unwind: '$commerce' } ]) .exec(callback); };
这个方案适合有复杂聚合需求的场景,一次数据库请求就能完成所有操作。
方案3:用mongoose populate的match选项(最贴合mongoose语法)
mongoose的populate支持match参数,可以在关联时过滤符合条件的Commerce,不过要注意:如果Offer关联的Commerce不匹配,commerce字段会变成null,所以最后需要过滤掉这些无效的Offer:
module.exports.getOffresByName = function(req, callback) { const name = req; Offre.find() .populate({ path: 'commerce', match: { name: name }, // 只关联名称匹配的Commerce select: 'name' // 可选:只返回Commerce的name字段,减少数据传输 }) .then(allOffers => { // 过滤掉commerce为null的Offer(这些Offer的关联Commerce名称不匹配) const validOffers = allOffers.filter(offer => offer.commerce !== null); callback(null, validOffers); }) .catch(err => callback(err)); };
这个方案用mongoose原生语法实现,更符合日常开发习惯。
内容的提问来源于stack exchange,提问作者Loïc Faidherbe
相关产品推荐
相关产品推荐

