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

IT技术 javascript node.js mongodb mongoose
2021-02-04 07:12:31

在mongoose中修改现有条目中的字段,使用有什么区别

model = new Model([...])
model.field = 'new value';
model.save();

还有这个

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

我问这个问题的原因是因为有人对我昨天发布的一个问题提出了建议:NodeJS 和 Mongo - 多个用户同时发送请求时的意外行为该人建议使用更新而不是保存,我还不确定为什么它会有所作为。

谢谢!

4个回答

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

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

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

此外,还有一个multi参数 to.update()允许对多个符合查询条件的文档执行操作。

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

总之.save()就是一个client端接口,.update()就是server端。

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

一些差异:

  • 正如其他地方所指出的,updatefind遵循更有效save因为它避免加载整个文档。
  • Mongooseupdate转换为 MongoDB,update但 Mongoosesave转换为 MongoDB insert(用于新文档)或update.
  • 需要注意的是,在 上saveMongoose 在内部对文档进行差异处理,并且只发送实际更改的字段。这有利于原子性。
  • 默认情况下不运行验证update但可以启用它。
  • 中间件 API(prepost钩子)是不同的。
给你的帽子提示
2021-04-14 07:12:31

Mongoose 有一个有用的功能叫做中间件。有“前”和“后”中间件。执行“保存”时会执行中间件,但不会在“更新”期间执行。例如,如果您想在每次修改密码时对 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();
    });
});
});
+1 谢谢user.isModified('password')一点。这让我发疯了。每次我试图保存一些东西时,密码都会改变。
2021-03-20 07:12:31
从 Mongoose 4.0 开始,还支持查询中间件(例如 for update)。
2021-04-06 07:12:31

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

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

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

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

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

因此,要小心!

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