Mongoose update() 真正更新了啥?

Posted

技术标签:

【中文标题】Mongoose update() 真正更新了啥?【英文标题】:What does Mongoose update() really update?Mongoose update() 真正更新了什么? 【发布时间】:2017-02-12 08:30:34 【问题描述】:

Mongoose 文档mention 这个示例代码:

Tank.findById(id, function (err, tank) 
  if (err) return handleError(err);

  tank.size = 'large';
  tank.save(function (err, updatedTank) 
    if (err) return handleError(err);
    res.send(updatedTank);
  );
);

这是否会导致 MongoDB update() 命令仅设置 size 属性(即 db.tanks.update(_id: tank._id, $set: size: "large");),还是会替换整个文档?

或者,换句话说,如果另一个客户端在findById() 返回之后但在save() 执行之前更新另一个属性(比如color)怎么办? color 是恢复到之前的值还是保持原样?

而且,如果 Mongoose 足够聪明,可以只更新“已更改”的属性,那么究竟是如何检测到的(在之前/之后比较值?还是通过 tank 对象上的设置器?)?如果坦克size 已经“大”了怎么办?

我问这个问题是因为 Mongoose docs 对此不是很清楚,我想了解 Mongoose 是如何设计打算在此使用尊重。

【问题讨论】:

自己测试应该比较容易。 如果我没有要测试的数据库,则不会。此外,测试并不能准确地揭示一个库应该做什么。糟糕的测试可能会导致错误的假设。 我怀疑除了 Mongoose 的开发人员之外,您是否会从任何人那里得到关于应该发生的确切答案,尤其是因为文档不是确定的。普通用户在此处发布的答案将是轶事。 【参考方案1】:

一些测试表明,Mongoose 跟踪对文档的修改(通过使用设置器,正如您已经提到的),并将运行 $set 的新值的更新。

所以这个:

tank.size = 'large';
tank.save(...);

(粗略地说)实现为:

tankCollection.update( _id : tank._id ,  $set :  size : 'large'  , ...);

如果size 之前的值也是large,则不会执行更新。此外,如果文档是新的,它将运行不同的代码路径(调用 tankCollection.insert())。

所以并发更新应该可以工作,前提是它们不更新相同的属性(在这种情况下,最后执行的更新获胜)。

【讨论】:

以上是关于Mongoose update() 真正更新了啥?的主要内容,如果未能解决你的问题,请参考以下文章

mongoose Model.update() - 只更新提供的值

使用 mongoose 通过 update 方法向 mongodb 中的现有文档添加新字段

使用 mongoose 通过 update 方法向 mongodb 中的现有文档添加新字段

Mongoose .update() 不会触发验证检查

mongoose update操作属性中的变量

Mongo/Mongoose Invalid atomic update value 错误