将字段乘以Mongodb中的值

将字段乘以Mongodb中的值,mongodb,Mongodb,我一直在寻找一种创建update语句的方法,该语句将接受现有的数字字段,并使用表达式对其进行修改。例如,如果我有一个名为Price的字段,是否可以进行更新,将Price设置为现有值的50% 因此,给定{Price:19.99} 我想做db.collection.update({tag:“refurb”},{$set{Price:Price*0.50},false,true) 这是可以做到的,还是我必须将值读回客户机,修改,然后更新?我想接下来的问题是,表达式是否可以用于更新,以及它们是否可以引用

我一直在寻找一种创建update语句的方法,该语句将接受现有的数字字段,并使用表达式对其进行修改。例如,如果我有一个名为Price的字段,是否可以进行更新,将Price设置为现有值的50%

因此,给定
{Price:19.99}

我想做
db.collection.update({tag:“refurb”},{$set{Price:Price*0.50},false,true)


这是可以做到的,还是我必须将值读回客户机,修改,然后更新?我想接下来的问题是,表达式是否可以用于更新,以及它们是否可以引用正在更新的文档。

您可以使用
db.eval()
运行服务器端代码

注意,这将阻塞数据库,因此最好执行查找更新操作对


请参见

好的,这在$set的原子操作中是可能的

您有几个选择:

  • 使用pingw33n提出的eval()解决方案
  • 检索要修改的文档以获取当前值,并使用集合修改它
  • 如果您的操作率很高,您可能希望确保在获取其值的过程中焦点没有发生变化(使用以前的解决方案),因此您可能希望使用findAndModify(请参阅获取有关如何操作的灵感)操作

这实际上取决于您的上下文:由于数据库压力很低,我会选择pingw33n的解决方案。由于手术率很高,我会使用第三种解决方案。

在新的Mongo2.6.x中有一个。它将使用以下语法将字段的值乘以数字

{
  $mul: { field: <number> }
}

启动
Mongo 4.2
,可以接受聚合管道,最后允许基于另一个字段更新字段:

// { price: 19.99 }
// { price: 2.04  }
db.collection.update(
  {},
  [{ $set: { price: { $multiply: [ 0.5, "$price" ] } } }],
  { multi: true }
)
// { price: 9.995 }
// { price: 1.02  }
  • 第一部分是匹配查询,过滤要更新的文档(本例中的所有文档)

  • 第二部分是更新聚合管道(注意方括号表示使用聚合管道)。是一个新的聚合运算符,别名为
    $addFields
    。请注意,
    price
    是如何根据其自身的值(
    $price
    )直接修改的

  • 不要忘记
    {multi:true}
    ,否则只会更新第一个匹配的文档


谢谢。你是说我应该像你所展示的那样使用eval(),还是应该在客户端使用find/update来避免阻塞?@Brad你应该评估这个特定更新操作的总体成本。如果操作很长(集合中的许多文档将被更新),则永远不要使用eval。首先查询一个文档,然后更新它,而不是就地更新,并没有太大的开销。特别是如果您限制查询大型文档的字段并使用covered index功能()很酷,谢谢。我还看到eval()不适用于切分,所以从长远来看,这排除了我的可能性。诺洛克是一个有趣的补充。这不是原子的。有关原子解决方案,请参见萨尔瓦多使用
$mul
的答案。谢谢。我不知道findAndModify如何允许使用表达式,这是我的主要目标。@Brad findAndModify允许使用表达式,但它允许执行两个阶段的操作:首先获取项目,然后更新它(减少50%),前提是它自检索以来没有更改。请注意,在即将发布的mongo版本中,您可以在不使用所有这些eval和DB锁定的情况下完成这项工作,几乎不需要任何成本。检查并可能接受新答案,这样新开发人员就不会使用过时的信息。
db.collection.update(
  { tag : "refurb"},
  { $mul: { Price : 0.5 } }
);
// { price: 19.99 }
// { price: 2.04  }
db.collection.update(
  {},
  [{ $set: { price: { $multiply: [ 0.5, "$price" ] } } }],
  { multi: true }
)
// { price: 9.995 }
// { price: 1.02  }