Chcesz .bulkWrite()
dla tego. W rzeczywistości nie jest to pojedyncza operacja, więc chcesz przesłać wiele operacji w jednym żądaniu. Zasadniczo spróbuj napisać aktualizację za pomocą $set
gdzie istnieją dane lub $push
nowe dane tam, gdzie nie istnieją:
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" } }
}
}}
])
Dodatni przypadek to po prostu wartość, a $ne
„neguje” dopasowanie równości, co oznacza, że element nie istnieje. Oczywiście pozycyjny $
operator
jest używany z $set
gdzie to robi
Biorąc pod uwagę dane, tylko jedna z operacji będzie pasować i zostanie zastosowana jako aktualizacja, mimo że dwie operacje są wysyłane w „paczce”.
Jeśli chcesz „upserts” również dla całego dokumentu, musisz na końcu dodać kolejną operację. Pamiętaj, że nie możesz zastosować „upsert” jako opcji w żadnej z pozostałych instrukcji, zwłaszcza $ne
ponieważ spowodowałoby to utworzenie nowego dokumentu, w którym element tablicy nie istnieje, a nie tylko _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
}}
])
$setOnInsert
jest tutaj główną pomocą, poza tą ostatnią operacją, która jest jedyną oznaczoną jako "upsert"
. Ta kombinacja zapewnia, że tam, gdzie zostanie znaleziony podstawowy „dokument”, tak naprawdę nic się nie dzieje, ale gdy nie zostanie znaleziony, dodawany jest nowy element tablicy.
Na marginesie, zdecydowanie sugerowałbym przechowywanie wartości liczbowych jako liczb, a nie ciągów. W większości przypadków nie tylko oszczędza miejsce, ale także jest o wiele bardziej przydatny w ten sposób.