MongoDB条件更新:仅最后价格不同时推送数组数据(支持Upsert)
MongoDB 数组更新问题解决
问题背景
现有MongoDB文档结构如下:
{ "accountName": "pippo", "whishList": { "element1": [ { "price": 25, "time": "2024-02-20T20:00:00.000+00:00" }, { "price": 30, "time": "2024-02-21T20:00:00.000+00:00" } ] } }
需要实现一个函数满足以下需求:
- 接收
price参数,仅当whishList.element1数组最后一个元素的price与传入值不同时,才向数组推送包含该price和当前时间的对象 - 若集合中不存在对应
accountName的文档,则自动创建(启用upsert: true)
原尝试代码无法正常运行:
async function updatePrice(id, element, price) { const filter = { accountName: id, $expr: { $ne: [ {$last : `whishList.${element}`}.price , price ] } } const update = { $push: { `whishList.${element}`: { value: valore, time: new Date() } } }; await prova.updateOne(filter, update, { upsert: true }); }
原代码问题分析
$expr语法错误:{$last : \whishList.${element}`}.price写法不符合MongoDB表达式规则,无法正确获取数组最后一个元素的price`字段- 字段名与变量错误:更新时误用了
value: valore,需求是price字段,且valore为未定义变量 - Upsert逻辑冲突:原过滤条件会导致文档不存在时,
$expr的判断无法触发upsert,需要调整逻辑覆盖空文档场景
修正后的代码
async function updatePrice(id, element, price) { const arrayPath = `whishList.${element}`; const filter = { accountName: id, $or: [ // 文档存在,数组最后一个元素price与传入值不同 { $expr: { $ne: [ { $getField: { field: "price", input: { $last: `$${arrayPath}` } } }, price ] } }, // 文档存在,但目标数组为空 { [arrayPath]: { $size: 0 } }, // 文档不存在,用于触发upsert { accountName: { $exists: false } } ] }; const update = { $setOnInsert: { // Upsert时初始化文档结构 whishList: { [element]: [] } }, $push: { [arrayPath]: { price: price, time: new Date() } } }; await prova.updateOne(filter, update, { upsert: true }); }
代码说明
- 多场景过滤:通过
$or覆盖三种需要更新/插入的情况,确保所有符合条件的场景都能命中 - 正确获取数组元素:用
$last结合$getField,准确提取数组最后一个元素的price字段进行比较 - 安全初始化:
$setOnInsert仅在创建新文档时初始化whishList结构,避免覆盖现有数据 - 字段修正:将错误的
value改为需求的price字段,使用传入的price参数
内容的提问来源于stack exchange,提问作者frangu77o
相关产品推荐
相关产品推荐

