web-dev-qa-db-fra.com

Différence de mangouste entre .save () et l'utilisation de update ()

Pour modifier un champ dans une entrée existante dans mangouste, quelle est la différence entre l'utilisation

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

et ça

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

La raison pour laquelle je pose cette question est à cause de la suggestion de quelqu'un à un problème que j'ai publié hier: NodeJS et Mongo - Comportements inattendus lorsque plusieurs utilisateurs envoient des demandes simultanément . La personne a suggéré d'utiliser la mise à jour au lieu de la sauvegarde, et je ne sais pas encore pourquoi cela ferait une différence.

Merci!

38
Edward Sun

Deux concepts d'abord. Votre application est le client , Mongodb est le serveur .

La principale différence est qu'avec .save() vous avez déjà un objet dans votre code côté client ou avez dû récupérer les données du serveur avant de le réécrire, et vous réécrivez le tout.

D'autre part, .update() ne pas nécessite que les données soient chargées sur le client à partir du serveur. Toutes les interactions se produisent côté serveur sans être récupérées sur le client. Ainsi, .update() peut être très efficace de cette manière lorsque vous ajoutez du contenu à des documents existants.

De plus, il existe le paramètre multi à .update() qui permet d'effectuer les actions sur plusieurs documents qui correspondent à la condition de requête.

Il y a certaines choses dans les méthodes pratiques que vous perdez lorsque vous utilisez .update() comme appel, mais les avantages pour certaines opérations sont le "compromis" que vous devez supporter. Pour plus d'informations à ce sujet et les options disponibles, consultez la documentation .

En bref .save() est une interface côté client, .update() est côté serveur.

92
Neil Lunn

Quelques différences:

  • Comme indiqué ailleurs, update est plus efficace que find suivi de save car il évite de charger tout le document.
  • Un Mongoose update se traduit par un MongoDB update mais un Mongoose save est converti en MongoDB insert (pour un nouveau document) ou en update.
  • Il est important de noter que sur save, Mongoose diffère en interne le document et envoie uniquement les champs qui ont réellement changé. C'est bon pour l'atomicité.
  • Par défaut la validation n'est pas exécutée sur update mais elle peut être activée.
  • L'API middleware (pre et post hooks) est différente.
30
Tamlyn

Il existe une fonctionnalité utile sur Mongoose appelée Middleware. Il existe des middleware "pré" et "post". Les middlewares sont exécutés lorsque vous effectuez une "sauvegarde", mais pas pendant la "mise à jour". Par exemple, si vous souhaitez hacher un mot de passe dans le schéma utilisateur chaque fois que le mot de passe est modifié, vous pouvez utiliser le pré pour le faire comme suit. Un autre exemple utile consiste à définir le lastModified pour chaque document. La documentation peut être trouvée sur 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

Un détail à ne pas prendre à la légère: simultanéité

Comme mentionné précédemment, lorsque vous effectuez une doc.save(), vous devez d'abord charger un document en mémoire, puis le modifier, et enfin, doc.save() les modifications apportées au serveur MongoDB.

Le problème se pose lorsqu'un document est modifié de cette façon simultanément :

  • La personne A charge le document (v1)
  • La personne B charge le document (v1)
  • La personne B enregistre les modifications apportées au document (il s'agit désormais de la version 2)
  • La personne A enregistre les modifications dans un document obsolète (v1)
  • La personne A verra Mongoose lancer une VersionError car le document a changé depuis le dernier chargement de la collection

La concurrence n'est pas un problème lors de l'exécution d'opérations atomiques comme Model.updateOne(), car l'opération est entièrement réalisée sur le serveur MongoDB, qui effectue un certain degré de contrôle de concurrence.

Attention donc!

0
Daniel