Javascript Mongoose.save()和使用update()之间的区别

Javascript Mongoose.save()和使用update()之间的区别,javascript,node.js,mongodb,mongoose,Javascript,Node.js,Mongodb,Mongoose,要修改mongoose中现有条目中的字段,使用 model = new Model([...]) model.field = 'new value'; model.save(); 还有这个 Model.update({[...]}, {$set: {field: 'new value'}); 我问这个问题的原因是因为有人对我昨天发布的一个问题提出了建议:。那个人建议使用更新而不是保存,我还不能完全确定为什么它会有不同 谢谢 首先是两个概念。您的应用程序是客户端,Mongodb是服务器 主要区

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

model = new Model([...])
model.field = 'new value';
model.save();
还有这个

Model.update({[...]}, {$set: {field: 'new value'});
我问这个问题的原因是因为有人对我昨天发布的一个问题提出了建议:。那个人建议使用更新而不是保存,我还不能完全确定为什么它会有不同


谢谢

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

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

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

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

使用
.update()
作为调用时,在方便的方法中会丢失一些东西,但某些操作的好处是必须进行“权衡”。有关这方面的详细信息以及可用选项,请参阅


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

Mongoose上有一个有用的特性,叫做中间件。有“pre”和“post”中间件。当您执行“保存”时会执行中间件,但不会在“更新”期间执行。例如,如果您想在每次修改密码时对用户模式中的密码进行散列,则可以使用pre按如下方式进行操作。另一个有用的示例是为每个文档设置lastModified。有关文件可在以下网址找到:

一些差异:

  • 如其他地方所述,
    update
    find
    后跟
    save
    更有效,因为它避免了加载整个文档
  • Mongoose
    update
    转换为MongoDB
    update
    ,但Mongoose
    save
    转换为MongoDB
    insert
    (对于新文档)或
    update
  • 需要注意的是,在
    保存
    时,只发送实际更改的字段。这有利于原子性
  • 默认情况下,
    更新
    ,但可以启用
  • 中间件API(
    pre
    post
    挂钩)是不同的

    • 一个不应轻视的细节:并发性

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

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

      • 人员A加载文档(v1)
      • 人员B加载文档(v1)
      • 人员B保存对文档的更改(现在是v2)
      • 人员A保存对过期(v1)文档的更改
      • 人员A将看到Mongoose抛出VersionError,因为文档自上次从集合中加载以来已发生更改
      在执行诸如
      Model.updateOne()
      之类的原子操作时,并发性不是问题,因为操作完全在MongoDB服务器中完成,该服务器执行一定程度的


      因此,当心

      我经常认为开源的一大优势是,你可以“走进”这个库,看看它是如何运作的。Mongoose文档甚至为许多功能提供了“显示源代码”链接。
      model=newmodel(…)
      不会更新任何内容,因为它会创建一个新文档。我认为如果没有这种混乱,这个问题会更好。这是一个很好的答案。您提供了上下文信息,这正是顶级指南和教程中通常缺少的信息…另一个我发现有用的
      multi
      参数是
      upsert
      (布尔值,默认为false),当设置为true时,在不满足查询条件时自动创建新文档。另一个有用的信息是save()会触发默认验证,而update要求您打开runvalidator。但即使在这种情况下,RunValidator也只有在使用某些关键字()时才会生效:“值得注意的最后一个细节是:更新验证器仅在$set和$unset操作(以及>=4.8.0中的$push和$addToSet)上运行。例如,下面的更新将成功,而不管number的值如何,因为更新验证器忽略$inc。”重要提示
      .save()
      不“写回全部内容”;它区分文档,只发送实际更改的字段。因此,可以使用它对数据库进行微小的更改,就像
      .update()
      @iss42一样。从Mongoose 4.0开始,还支持查询中间件(例如用于
      更新
      )。+1感谢
      用户.isModified('password')
      位。这让我发疯。每次我试图保存一些东西时,密码都在更改。敬请见谅
      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();
          });
      });
      });