Mongo Mongoose:如何在条件中为$in操作符动态选取值?
MongoDB $in 传入客户端数组失效的问题解决
问题核心
你遍历键值对对象时,想通过$in判断title是否已存在于数据库的reports数组中,不存在则添加对应对象。硬编码字符串时功能正常,但传入客户端map生成的condition数组时,所有对象都会被保存,完全失效。
原因
MongoDB的聚合管道(即findOneAndUpdate第二个参数的数组式操作)无法直接识别客户端的JavaScript变量:
- 硬写字符串时,值是直接嵌入聚合表达式的,服务器能正常解析;
condition是客户端生成的数组,服务器端的聚合管道看不到这个变量,会把它当成字面量处理,导致$in判断永远不成立,每次都执行添加操作。
解决方案
方案一:将客户端变量注入聚合管道
通过$set把condition注入到聚合上下文,让服务器能访问到该数组:
for (let key in reports) { const condition = reports[key].map(x => x.title); await Product.findOneAndUpdate( { "name": key }, [ // 注入临时字段存储客户端数组 { "$set": { "_tempTitles": condition } }, { "$set": { "reports": { "$cond": [ // 引用注入的临时字段进行判断 { "$in": ["$_tempTitles", "$reports.title"] }, "$reports", { "$concatArrays": ["$reports", reports[key]] } ] }, // 删除临时字段 "_tempTitles": "$$REMOVE" } } ], { new: true } ); }
方案二:客户端先过滤再更新(更直观)
先查询已有的title列表,在客户端过滤掉重复对象后再更新,逻辑更清晰:
for (let key in reports) { // 查询目标产品已有的title集合 const product = await Product.findOne({ "name": key }, { "reports.title": 1 }); const existingTitles = product ? product.reports.map(x => x.title) : []; // 过滤掉已存在title的对象 const newReports = reports[key].filter(x => !existingTitles.includes(x.title)); if (newReports.length === 0) continue; // 无新内容则跳过更新 // 仅添加过滤后的新对象 await Product.findOneAndUpdate( { "name": key }, { "$push": { "reports": { "$each": newReports } } }, { new: true } ); }
内容的提问来源于stack exchange,提问作者user6377312
相关产品推荐
相关产品推荐

