Supposons que nous ayons la collection suivante, sur laquelle j'ai quelques questions:
{
"_id" : ObjectId("4faaba123412d654fe83hg876"),
"user_id" : 123456,
"total" : 100,
"items" : [
{
"item_name" : "my_item_one",
"price" : 20
},
{
"item_name" : "my_item_two",
"price" : 50
},
{
"item_name" : "my_item_three",
"price" : 30
}
]
}
1 - Je souhaite augmenter le prix de "item_name": "my_item_two" et s'il n'existe pas , il doit être ajouté au tableau "items".
2 - Comment mettre à jour deux champs en même temps. Par exemple, augmentez le prix de "my_item_three" et en même temps augmentez le "total" (avec la même valeur).
Je préfère le faire du côté de MongoDB, sinon je dois charger le document côté client (Python) et construire le document mis à jour et le remplacer par celui existant dans MongoDB.
MISE À JOUR Voici ce que j'ai essayé et qui fonctionne très bien SI l'objet existe :
db.test_invoice.update({user_id : 123456 , "items.item_name":"my_item_one"} , {$inc: {"items.$.price": 10}})
Mais si la clé n'existe pas, elle ne fait rien. De plus, il ne met à jour que l'objet imbriqué. Il n'y a aucun moyen avec cette commande de mettre à jour le champ "total" également.
Réponses:
Pour la question n ° 1, divisons-la en deux parties. Tout d'abord, incrémentez tout document qui a "items.item_name" égal à "my_item_two". Pour cela, vous devrez utiliser l'opérateur positionnel "$". Quelque chose comme:
Notez que cela n'incrémentera que le premier sous-document correspondant dans n'importe quel tableau (donc si vous avez un autre document dans le tableau avec "item_name" égal à "my_item_two", il ne sera pas incrémenté). Mais c'est peut-être ce que vous voulez.
La deuxième partie est plus délicate. Nous pouvons pousser un nouvel élément vers un tableau sans "my_item_two" comme suit:
Pour votre question n ° 2, la réponse est plus simple. Pour incrémenter le total et le prix de item_three dans tout document contenant "my_item_three", vous pouvez utiliser l'opérateur $ inc sur plusieurs champs en même temps. Quelque chose comme:
la source
Il n'y a aucun moyen de le faire en une seule requête. Vous devez rechercher le document dans la première requête:
Si le document existe:
Autre
Pas besoin d'ajouter de condition
{$ne : "my_item_two" }
.De plus, dans un environnement multithread, vous devez faire attention à ce qu'un seul thread puisse exécuter le second (insérer la casse, si le document n'a pas été trouvé) à la fois, sinon des documents incorporés en double seront insérés.
la source
Nous pouvons utiliser l'
$set
opérateur pour mettre à jour le tableau imbriqué à l'intérieur de l'objet déposé mettre à jour la valeurla source