如何在MongoDB中仅更新嵌套对象中已存在的属性?
MongoDB实现仅更新已存在字段($setIfExists等效效果)
MongoDB原生没有提供$setIfExists操作符,但可以通过4.2及以上版本支持的聚合管道更新实现需求,仅修改嵌套字段下已存在的属性,不会新增字段。
实现代码
// 1. 预先定义要更新的字段和对应新值 const updateMap = { val1: 12, val2: 22, val3: 32 }; // 2. 执行更新操作 col.updateMany( { _id: { $in: [1, 2] } }, // 第二个参数传入聚合管道数组 [ { $set: { obj: { $mergeObjects: [ "$obj", // 保留原obj中不需要更新的字段 { $arrayToObject: { $map: { // 过滤出原obj中存在于更新列表里的字段 input: { $filter: { input: { $objectToArray: "$obj" }, cond: { $in: [ "$$this.k", Object.keys(updateMap) ] } } }, // 把过滤后的字段值替换为新值 in: { k: "$$this.k", v: { $getField: { input: updateMap, field: "$$this.k" } } } } } } ] } } } ] )
逻辑说明
- 先通过
$objectToArray把原文档的obj嵌套对象转为[{k:"键名", v:"原值"}]格式的数组,方便遍历处理 - 用
$filter过滤出数组中键名在预设更新列表里的项,排除原obj中不存在的键 - 用
$map把过滤后的项的原值替换为预设的新值 - 再通过
$arrayToObject把处理后的数组转回对象格式 - 最后用
$mergeObjects把新的键值对合并到原obj对象上,完成更新
低版本兼容说明
如果你的MongoDB版本低于5.0(不支持$getField操作符),可以提前遍历要更新的键,构造条件分支实现,或者先查询出符合条件的文档的obj键列表,再针对性构造$set参数执行更新,该方案适合小数据量场景。
内容的提问来源于stack exchange,提问作者Stefan
相关产品推荐
相关产品推荐

