Vuoi .bulkWrite()
per questo. Questa non è in realtà una singola operazione, quindi si desidera inviare più operazioni in un'unica richiesta. In sostanza, prova a scrivere l'aggiornamento con $set
dove esistono dati o $push
i nuovi dati dove non esistono:
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" } }
}
}}
])
Il caso positivo è semplicemente il valore e il $ne
"nega" la corrispondenza di uguaglianza, il che significa che l'elemento non esiste. Naturalmente il posizionale $
operatore
viene utilizzato con $set
dove lo fa
Dati i dati, solo una delle operazioni corrisponderà effettivamente e si applicherà come aggiornamento nonostante due operazioni vengano inviate nel "batch".
Se vuoi anche "upsert" per l'intero documento, devi aggiungere un'altra operazione alla fine. Tieni presente che non puoi applicare "upsert" come opzione su nessuna delle altre affermazioni, in particolare su $ne
perché ciò creerebbe un nuovo documento in cui l'elemento dell'array non esiste, non solo il _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
}}
])
Il $setOnInsert
è l'aiuto principale qui a parte che l'ultima operazione è l'unica contrassegnata come "upsert"
. Questa combinazione fa in modo che dove si trova il "documento" primario non accada nulla, ma quando non viene trovato viene aggiunto il nuovo elemento dell'array.
Come nota a margine, suggerirei vivamente di memorizzare i valori numerici effettivamente come numerici anziché come stringhe. Non solo fa risparmiare spazio nella maggior parte dei casi, ma è anche molto più utile in questo modo.