.save()和使用update()之间的猫鼬差异

时间:2014-03-09 05:25:03

标签: javascript node.js mongodb mongoose

要修改mongoose中现有条目中的字段,使用

之间有什么区别
model = new Model([...])
model.field = 'new value';
model.save();

和这个

Model.update({[...]}, {$set: {field: 'new value'});

我问这个问题的原因是因为有人建议我昨天发布的问题:NodeJS and Mongo - Unexpected behaviors when multiple users send requests simultaneously。这个人建议使用更新而不是保存,我还不完全确定它为什么会有所作为。

谢谢!

4 个答案:

答案 0 :(得分:87)

首先是两个概念。您的应用是客户端,Mongodb是服务器

主要的区别在于,.save()您的客户端代码中已经有了一个对象,或者在您将其写回之前必须从服务器检索数据,并且您正在回写整个事情。 / p>

另一方面,.update() 要求将数据从服务器加载到客户端。所有的交互都发生在服务器端而没有检索到客户端。当您向现有文档添加内容时,.update()以这种方式非常有效。

此外,multi的{​​{1}}参数允许对多个与查询条件匹配的文档执行操作。

在使用.update()作为通话时,您可以放松一些方便方法,但某些操作的好处是您必须承担的“权衡”。有关此内容以及可用选项的详细信息,请参阅documentation

简而言之.update()是客户端界面,.save()是服务器端。

答案 1 :(得分:29)

一些差异:

  • 如其他地方所述,update效率高于find,后跟save,因为它可以避免加载整个文档。
  • 一个Mongoose update转换为MongoDB update但Mongoose save转换为MongoDB insert(用于新文档)或update }。
  • saveMongoose internally diffs the document上注意并且仅发送实际已更改的字段非常重要。这对原子性有好处。
  • update上的默认validation is not run,但可以启用。
  • 中间件API(prepost挂钩)不同。

答案 2 :(得分:12)

Mongoose上有一个名为Middleware的有用功能。有'pre'和'post'中间件。当您执行“保存”时,中间件会被执行,但在“更新”期间不会执行。例如,如果要在每次修改密码时在User模式中哈希密码,可以使用pre来执行以下操作。另一个有用的示例是为每个文档设置lastModified。可以在http://mongoosejs.com/docs/middleware.html

找到该文档
UserSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) {
    console.log('password not modified');
    return next();
}
console.log('password modified');
// generate a salt
bcrypt.genSalt(10, function(err, salt) {
    if (err) {
        return next(err);
    }

    // hash the password along with our new salt
    bcrypt.hash(user.password, salt, function(err, hash) {
        if (err) {
            return next(err);
        }
        // override the cleartext password with the hashed one
        user.password = hash;
        next();
    });
});
});

答案 3 :(得分:3)

一个不应掉以轻心的细节:并发

如前所述,在执行doc.save()时,您必须先将文档加载到内存中,然后对其进行修改,最后,doc.save()对MongoDB服务器进行更改。

以这种方式同时编辑文档时会出现此问题:

  • 人员A加载文档(v1)
  • 人员B加载文档(v1)
  • 人员B将更改保存到文档(现在为v2)
  • 人员A将更改保存到过时的(v1)文档中
  • 人员A将看到Mongoose抛出VersionError,因为自从上次从集合中加载文档以来,文档已更改

在进行诸如Model.updateOne()之类的原子操作时,并发不是问题,因为该操作完全在MongoDB服务器中完成,该服务器执行一定程度的 concurrency control 。< / p>

因此,请当心!