MongoDB:如果字段值小于10,则将字段值设置为10,否则加1

问题描述 投票:0回答:2

考虑以下代码:

findAndModify({id: id}, undefined, {$inc: {counter: 1}, {$max: {counter: 10})

此操作会失败并出现错误,因为

$inc
$max
都尝试更新同一字段。

但是,如果我想在计数器的值小于 10 时将其设置为 10,如果不是,则将其值增加 1,该怎么办?我如何在一个原子操作中做到这一点?

有没有办法在一次操作中按顺序应用更新?

node.js mongodb mongoose nosql mongodb-query
2个回答
2
投票

我认为这不可能通过一次操作来完成。但是,您可以使用条件语句创建聚合查询,然后在更新中使用。

(async () => {
    try {
        const results = await Model.aggregate([
            { '$match': { 'id': id } },
            { '$project': { 
                'counter': { 
                    '$cond': [
                        { '$lt': ['$counter', 10 ] },
                        10,
                        { '$add': ['$counter', 1 ] }
                    ] 
                }
            } }
        ]).exec();

        const data = results[0];
        const { counter } = data;

        const doc = await Model.findOneAndUpdate({ id },
            { '$set': { counter } },
            { new: true }
        ).exec();

        console.log(doc);
    } 
    catch (err) {
        console.error(err);
    }
})()

对于原子更新,包括一个查询,该查询限制仅具有

counter
小于给定上限值 10 的文档的增量:

findAndModify(
    {
        'id': id,
        'counter': { '$lt': 10 } 
    }, undefined, 
    { '$inc': { 'counter': 1 } },
    callback
)

0
投票

添加 MongoDB 最新版本的答案。 4.4 的网络存档显示相同

从 MongoDB 4.2(~2019)开始,您可以将

update()
与聚合管道一起使用。使用它,更新变得原子,因为只有一个条件适用,而不是两者都适用。

使用

$cond
,并检查
counter < 10
,更新操作看起来与之前的旧答案类似,但作为一个操作。请注意在 update 子句周围使用
[ ... ]
以使用该命令的管道版本;它允许引用文档值和其他变量。

db.collection.update({
  _id: 1
},
[
  {
    $set: {
      counter: {
        $cond: {
          if: { $lt: ["$counter", 10] },
          then: 10,
          else: { $add: ["$counter", 1] }
        }
      }
    }
  }
])

具有多个文档的Mongo Playground

这可以转换为类似于现有更新查询的内容,使用

$max
$add
并给出相同的结果。在这里,从
(10, current + 1)
中选择最大值:

  • 从 -无穷大到 8 的数字加上
    1
    将得到小于 10 的结果;所以选择了10个
  • 添加
    1
    的从 10 到 +无穷大的数字将得到大于 10 的结果,因此选择
    +1
  • 对于
    9
    ,比较是在 10 和 10 (9+1) 之间,所以是 10。
db.collection.update({
  _id: 1
},
[
  {
    $set: {
      counter: { $max: [{ $add: ["$counter", 1] }, 10] }
    }
  }
])

具有多个文档的替代 Mongo Playground

要对每个文档执行一次更新查询,请从查询参数中删除

_id
并将其保留为所有文档
{}
,如链接的 Playground 中所做的那样。

© www.soinside.com 2019 - 2024. All rights reserved.