首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用$inc运算符在MongoDB中生成更新命令?

如何使用$inc运算符在MongoDB中生成更新命令?
EN

Stack Overflow用户
提问于 2022-08-24 12:05:03
回答 2查看 35关注 0票数 1

众所周知,$inc$mul$add运算符的update命令在MongoDB中不是幂等的。我们想知道如何使用update操作符幂等函数来生成$inc命令。

给定一个文档users的集合{"_id" : "123", "age" : 24, "name": "me"},我们希望通过db.users.update({_id: "123"}, {$inc: {age: 1}})age增加1。显然,这个update命令不是幂等的,因为当这个update命令意外执行两次时,age将增加2。

我们尝试过的。

  • $set代替$inc,因为$set运算符可以被认为是幂等的。

var doc = db.users.findOne({_id:"123"}) var oldAge = doc.age var newAge = oldAge +1 db.users.updateOne({_id:"123",age: oldAge},{$set:{ age: newAge})

但是,该解决方案未能保持update命令的幂等性。

  • 添加了一个像"op": "pending"这样的字段作为锁,op的默认值是none,意味着这个文档上没有操作。当尝试增加age时,将op的值设置为“挂起”,然后在完成增加操作后将其重置为none

var doc = db.users.findOne({_id:"123","op":“无”}) if (doc.op === "none") { db.users.updateOne({_id:"123"},{$set:{ op:‘未决’}) db.users.updateOne({_id:"123",op:‘未决’},{$inc:{age: 1},$set:{ op:‘none’}

此解决方案的问题是很难使上述操作保持原子化。。

  • 添加了一个像"version": 1这样的字段,作为一个乐观锁。

而{ var doc = db.users.findOne({_id:"123"}) var curVersion = doc.version +1 db.users.updateOne({_id:"123"},{$set:{ version: curVersion}) var = db.users.updateOne({_id:"123",version: curVersion},{$inc:{age: 1}}) if (ret.modifiedCount == 1) { break;}}

这个解决方案的问题是,当存在多个simutinaously.操作inc时,效果会很差。

是否有更好的解决办法使update命令具有$inc运算符幂等性?

这个需求是基于在我的示例中使用AWS documentDB的实际情况,在维护期间,documentDB的主节点无法在几秒钟内可用。对于AWS支持人员,我们应该在重试策略中使用带有update操作符的$inc命令来处理维护期间的update命令失败。

EN

Stack Overflow用户

发布于 2022-08-24 12:26:23

您所描述的这个用例和边缘案例听起来非常奇怪,但下面是我如何处理这样一个问题的方法:

对于您想要更新的每个字段,您必须以某种方式跟踪它的最后一个更新--否则永远无法保证不会发生多个更新,最简单的方法是在文档中添加一个字段,但这也可以在一个单独的集合中跟踪。对于这个答案,我假设只有age字段可以是$inc'd。

因此,正如我前面提到的,我会添加age_update_time,然后我就可以不担心地执行以下更新:

代码语言:javascript
运行
复制
const aYearAgo = new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 365)
db.users.updateOne(
    {
        _id: "123",
        $or: [
            {   // either it's been a year since last update.
                age_update_time: {$gt: aYearAgo}
            },
            {   // or an update is due.
                age_update_time: {$exists: false}
            }
        ]
    },
    {
        $set: {
            age_update_time: new Date()
        },
        $inc: {
            age: 1
        }
    }
)

因为mongo的更新是原子的,所以保证每年只执行一次更新。

同样,正如前面提到的,这个usecase听起来很奇怪,我知道这可能是一个玩具的例子-但是如果您能够分享更多关于为什么在您的系统中存在这种行为的细节,我也许可以提供更好的建议。

票数 2
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73472843

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档