MongoDB中更新空数组元素时无法应用upsert问题求助
问题分析
你当前的更新逻辑依赖arrayFilters匹配数组元素,但当markets为空数组时,没有任何元素能满足element.eventId:1的过滤条件,所以$set: {"markets.$[element]": ...}这一步不会执行。而upsert: true仅作用于「整个文档不存在」的场景,并非数组元素不存在的情况,因此空数组时文档不会有变化。
只有当数组中已存在eventId:1的元素时,arrayFilters能匹配到目标元素,$set才能正常更新该元素。
解决方案
要实现「数组中无匹配元素则插入,有则更新」的逻辑,需要使用MongoDB 4.2+支持的聚合管道式更新,通过条件判断处理两种场景:
db.collection.update( { id: 10 }, [ { $set: { markets: { $cond: { // 判断数组中是否存在eventId=1的元素 if: { $in: [1, "$markets.eventId"] }, // 存在则遍历数组更新匹配元素 then: { $map: { input: "$markets", as: "item", in: { $cond: { if: { $eq: ["$$item.eventId", 1] }, then: { eventId: 1, happy: 2 }, else: "$$item" } } } }, // 不存在则将新元素追加到数组 else: { $concatArrays: ["$markets", [{ eventId: 1, happy: 2 }]] } } } } } ], { upsert: true } )
逻辑说明
- 判断目标元素是否存在:用
$in检查markets.eventId集合里是否包含1; - 存在则更新:用
$map遍历数组,匹配到eventId=1的元素时替换为新对象,其余元素保持原样; - 不存在则插入:用
$concatArrays将新元素追加到原数组末尾(空数组时直接生成包含新元素的数组); - 全文档不存在时自动创建:
upsert: true依然生效,若id:10的文档完全不存在,会自动创建该文档并初始化markets为包含目标元素的数组。
测试验证
- 初始数据为空数组时:执行后
markets会变为[{eventId:1, happy:2}]; - 数组已存在
eventId:1的元素时:该元素会被更新为{eventId:1, happy:2}; - 目标文档不存在时:会自动插入
{id:10, markets:[{eventId:1, happy:2}]}的新文档。
内容的提问来源于stack exchange,提问作者TungTung
相关产品推荐
相关产品推荐

