.save() 和使用 update() 之间的猫鼬区别

Posted

技术标签:

【中文标题】.save() 和使用 update() 之间的猫鼬区别【英文标题】:Mongoose difference between .save() and using update() 【发布时间】:2014-04-12 07:01:29 【问题描述】:

修改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。该人建议使用更新而不是保存,我还不完全确定为什么会有所作为。

谢谢!

【问题讨论】:

我经常认为开源的一大优势是您可以“进入”库并查看它的运行情况。 Mongoose 文档甚至为许多功能提供了“显示源代码”链接。 model = new Model(...) 不会更新任何内容,因为它会创建一个新文档。我认为如果没有这种混淆,这个问题会更好。 【参考方案1】:

首先是两个概念。你的应用是Client,Mongodb是Server

主要区别在于,使用.save(),您的客户端代码中已经有一个对象,或者必须在回写之前从服务器检索数据,而您正在回写整个内容。

另一方面,.update()要求将数据从服务器加载到客户端。所有交互都发生在服务器端,无需检索到客户端。因此,当您将内容添加到现有文档时,.update() 可以非常高效。

此外,.update()multi 参数允许对多个与查询条件匹配的文档执行操作。

在使用.update() 作为调用时,您会失去便利方法中的一些东西,但某些操作的好处是您必须承担的“权衡”。有关这方面的更多信息以及可用选项,请参阅documentation。

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

【讨论】:

这是一个很好的答案。您提供了 context 信息,而这正是***指南和教程中通常缺少的信息... 另一个我发现有用的multi 参数是upsert(布尔值,默认为false),当它设置为true时,它会自动创建一个新文档不满足查询条件。 另一件有用的事情是 save() 触发默认验证,而 update 要求您打开 runValidators。但即使在这种情况下,runValidators 也只有在您使用某些关键字 (mongoosejs.com/docs/validation.html#update-validators) 时才会生效:“最后一个值得注意的细节:更新验证器仅在 $set 和 $unset 操作上运行(以及 >= 中的 $push 和 $addToSet 4.8.0)。例如,无论 number 的值如何,下面的更新都会成功,因为更新验证器会忽略 $inc。" 重要提示 .save() 不是写回整个事情” ;它区分文档并仅发送实际更改的字段。所以可以用来对数据库进行微小的更改,就像.update()一样。 @iss42 在这里。 github.com/Automattic/mongoose/blob/…【参考方案2】:

一些区别:

如其他地方所述,updatefind 后跟 save 更有效,因为它避免了加载整个文档。 Mongoose update 转换为 MongoDB update,但 Mongoose save 转换为 MongoDB insert(用于新文档)或 update。 需要注意的是,save、Mongoose internally diffs the document 只发送实际更改的字段。这有利于原子性。 默认情况下validation is not run on update 但可以启用。 中间件 API(prepost 挂钩)不同。

【讨论】:

向你致敬【参考方案3】:

Mongoose 上有一个很有用的功能,叫做中间件。有“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();
    );
);
);

【讨论】:

从 Mongoose 4.0 开始,还支持查询中间件(例如 update)。 +1 感谢user.isModified('password') 位。这让我发疯了。每次我尝试保存某些内容时,密码都会更改。【参考方案4】:

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

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

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

A 人加载文档 (v1) B 人加载文档 (v1) B 保存对文档的更改(现在是 v2) 人员 A 将更改保存到过时 (v1) 文档中 人员 A 将看到 Mongoose 抛出 VersionError,因为该文档自上次从集合中加载后发生了更改

在做Model.updateOne()这样的原子操作时并发不是问题,因为操作完全在MongoDB服务器中完成,执行一定程度的concurrency control

因此,小心!

【讨论】:

在这种情况下,有没有像Model.updateOne()那样只使用原子操作的公司呢?或者只是需要记住的事情?当我需要首先查询文档以进行条件更改时,我发现很难使用原子操作。只是好奇我是否应该继续努力只使用 atomic,或者可以同时使用两者,记住尽可能使用 atomic。

以上是关于.save() 和使用 update() 之间的猫鼬区别的主要内容,如果未能解决你的问题,请参考以下文章

hibernateHibernate中save, saveOrUpdate, persist, merge, update 区别

django rest框架中的save()、create()和update()有啥区别?

如何提高 MongoDB 中 update() 和 save() 的性能?

Django中update和save()同时作用

hibernate save,update,saveorupdate方法有什么区别

Hibernate三种状态的区分,以及save,update,saveOrUpdate,merge等的使用 ----转----