web-dev-qa-db-ja.com

.save()とupdate()の使用のマングースの違い

Mongooseの既存のエントリのフィールドを変更するには、使用することの違いは何ですか

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

この

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

私がこの質問をしている理由は、昨日投稿した問題に対する誰かの提案のためです: NodeJSとMongo-複数のユーザーが同時にリクエストを送信するときの予期しない動作 。その人は、保存の代わりに更新を使用することを提案しましたが、なぜそれが違いを生むのか完全にはわかりません。

ありがとう!

38
Edward Sun

最初に2つの概念。アプリケーションはClient、MongodbはServerです。

主な違いは、.save()を使用すると、すでにクライアント側コードにオブジェクトがあるか、書き戻す前にサーバーからデータを取得する必要があり、すべてを書き戻すことです。

一方、.update()は、サーバーからクライアントにデータをロードすることをnot必要とします。すべての対話はクライアントに取得せずにサーバー側で行われます。したがって、既存のドキュメントにコンテンツを追加する場合、.update()はこの方法で非常に効率的になります。

さらに、multiパラメータが.update()にあり、クエリ条件に一致する複数のドキュメントでアクションを実行できます。

.update()を呼び出しとして使用するときに失う便利なメソッドにはいくつかのものがありますが、特定の操作の利点は、負担する必要がある「トレードオフ」です。これと使用可能なオプションの詳細については、 documentation を参照してください。

要するに、.save()はクライアント側のインターフェースであり、.update()はサーバー側です。

92
Neil Lunn

いくつかの違い:

  • 他の箇所で述べたように、updatefindの後にsaveが続くよりも効率的です。これは、ドキュメント全体の読み込みを回避するためです。
  • Mongoose updateはMongoDB updateに変換されますが、Mongoose saveはMongoDB insert(新しいドキュメントの場合)またはupdate
  • saveでは、 Mongooseは内部的にドキュメントを差分します であり、実際に変更されたフィールドのみを送信することに注意することが重要です。これは原子性に適しています。
  • デフォルトでは 検証は実行されません on updateが有効にできます。
  • ミドルウェアAPI(preおよびpostフック)は異なります。
30
Tamlyn

Mongooseにはミドルウェアと呼ばれる便利な機能があります。 「pre」および「post」ミドルウェアがあります。ミドルウェアは、「更新」中ではなく「保存」を行うと実行されます。たとえば、パスワードが変更されるたびにユーザースキーマでパスワードをハッシュする場合、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();
    });
});
});
15

軽視してはならない1つの詳細:concurrency

前述したように、doc.save()を実行するときは、最初にドキュメントをメモリにロードしてから変更し、最後にdoc.save() MongoDBサーバーへの変更を行う必要があります。

ドキュメントがそのように編集されたときに問題が発生します同時に

  • 人Aがドキュメントを読み込みます(v1)
  • 人Bがドキュメントを読み込みます(v1)
  • ユーザーBがドキュメントへの変更を保存します(現在はv2です)
  • 人Aが古い(v1)文書への変更を保存する
  • コレクションから最後にロードされてからドキュメントが変更されたため、A人はMongooseがVersionErrorをスローするのを確認します。

Model.updateOne()のようなアトミック操作を実行する場合、同時性は問題ではありません。これは、特定の同時実行制御を実行するMongoDBサーバーで操作が完全に実行されるためです

したがって、注意してください!

0
Daniel