.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】:
一些区别:
如其他地方所述,update
比 find
后跟 save
更有效,因为它避免了加载整个文档。
Mongoose update
转换为 MongoDB update
,但 Mongoose save
转换为 MongoDB insert
(用于新文档)或 update
。
需要注意的是,save
、Mongoose internally diffs the document 只发送实际更改的字段。这有利于原子性。
默认情况下validation is not run on update
但可以启用。
中间件 API(pre
和 post
挂钩)不同。
【讨论】:
向你致敬【参考方案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() 的性能?
hibernate save,update,saveorupdate方法有什么区别
Hibernate三种状态的区分,以及save,update,saveOrUpdate,merge等的使用 ----转----