U wilt .bulkWrite()
voor deze. Dit is eigenlijk geen enkele bewerking, dus u wilt meerdere bewerkingen in één verzoek indienen. Probeer in wezen de update te schrijven met $set
waar gegevens bestaan of $push
de nieuwe gegevens waar ze niet bestaan:
db.collection.bulkWrite([
{ "updateOne": {
"filter": { "_id": "1", "option.weight": "10" },
"update": {
"$set": { "option.$.price": "30" }
}
}},
{ "updateOne": {
"filter": { "_id": "1", "option.weight": { "$ne": "10" } },
"update": {
"$push": { "option": { "weight": "10", "price": "30" } }
}
}}
])
Het positieve geval is gewoon de waarde, en de $ne
"negeert" de gelijkheidsovereenkomst, wat betekent dat het item niet bestaat. Natuurlijk de positionele $
operator
wordt gebruikt met $set
waar het doet
Gezien de gegevens zal slechts één van de bewerkingen daadwerkelijk overeenkomen en als een update worden toegepast, ondanks dat er twee bewerkingen in de "batch" worden verzonden.
Als je ook "upserts" voor het hele document wilt, dan moet je daar nog een bewerking aan toevoegen. Merk op dat u "upsert" niet als optie kunt toepassen op een van de andere instructies, met name de $ne
omdat dat een nieuw document zou creëren waarin het array-item niet bestaat, niet alleen de _id
:
db.collection.bulkWrite([
{ "updateOne": {
"filter": { "_id": "1", "option.weight": "10" },
"update": {
"$set": { "option.$.price": "30" }
}
}},
{ "updateOne": {
"filter": { "_id": "1", "option.weight": { "$ne": "10" } },
"update": {
"$push": { "option": { "weight": "10", "price": "30" } }
}
}},
{ "updateOne": {
"filter": { "_id": 1 },
"update": {
"$setOnInsert": {
"option": [
{ "weight": "10", "price": "30" }
]
}
},
"upsert": true
}}
])
De $setOnInsert
is de belangrijkste hulp hier, behalve dat die laatste bewerking de enige is die is gemarkeerd als "upsert"
. Die combinatie zorgt ervoor dat waar het primaire "document" wordt gevonden, er niets gebeurt, maar wanneer het niet wordt gevonden, wordt het nieuwe array-item toegevoegd.
Als een kanttekening zou ik sterk aanbevelen om numerieke waarden eigenlijk als numeriek op te slaan in plaats van strings. Het bespaart in de meeste gevallen niet alleen ruimte, maar is op die manier ook veel nuttiger.