Vous ne pouvez pas faire référence aux valeurs du document que vous souhaitez mettre à jour, vous aurez donc besoin d'une requête pour récupérer le document et d'une autre pour le mettre à jour. Il semble qu'il y ait une demande de fonctionnalité
pour cela en OPEN
état depuis 2016.
Si vous avez une collection avec des documents qui ressemblent à :
{ "_id" : ObjectId("590a4aa8ff1809c94801ecd0"), "name" : "bar" }
En utilisant le shell MongoDB, vous pouvez faire quelque chose comme ceci :
db.test.find({ name: "bar" }).snapshot().forEach((doc) => {
doc.name = "foo-" + doc.name;
db.test.save(doc);
});
Le document sera mis à jour comme prévu :
{ "_id" : ObjectId("590a4aa8ff1809c94801ecd0"), "name": "foo-bar" }
Notez le .snapshot()
call. Cela garantit que la requête ne renverra pas un document plusieurs fois, car une opération d'écriture intermédiaire le déplace en raison de la croissance de la taille du document.
En appliquant cela à votre exemple Mongoose, comme expliqué dans cet exemple officiel :
Cat.findById(1, (err, cat) => {
if (err) return handleError(err);
cat.name = cat.name + "bar";
cat.save((err, updatedCat) => {
if (err) return handleError(err);
...
});
});
Il convient de mentionner qu'il existe un $concat
opérateur dans le cadre d'agrégation, mais malheureusement, vous ne pouvez pas l'utiliser dans une update
requête.
Quoi qu'il en soit, selon ce que vous devez faire, vous pouvez l'utiliser avec le $out
opérateur pour enregistrer les résultats de l'agrégation dans une nouvelle collection.
Avec ce même exemple, vous ferez :
db.test.aggregate([{
$match: { name: "bar" }
}, {
$project: { name: { $concat: ["foo", "-", "$name"] }}
}, {
$out: "prefixedTest"
}]);
Et une nouvelle collection prefixedTest
sera créé avec des documents qui ressemblent à :
{ "_id" : ObjectId("XXX"), "name": "foo-bar" }
Juste comme référence, il y a une autre question intéressante sur ce même sujet avec quelques réponses qui valent la peine d'être lues :Mettre à jour le champ MongoDB en utilisant la valeur d'un autre champ