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!
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.
Quelques différences:
update
est plus efficace que find
suivi de save
car il évite de charger tout le document.update
se traduit par un MongoDB update
mais un Mongoose save
est converti en MongoDB insert
(pour un nouveau document) ou en update
.save
, Mongoose diffère en interne le document et envoie uniquement les champs qui ont réellement changé. C'est bon pour l'atomicité.update
mais elle peut être activée.pre
et post
hooks) est différente.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();
});
});
});
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 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!