Hlavním problémem je, že findOneAndUpdate
dělá přesně to, co jeho název napovídá. Provede find
pomocí poskytnutého filtru, a pokud je nalezena shoda, použije aktualizace na první odpovídající dokument.
Pokud sbírka obsahuje pouze tento dokument:
[
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_02",
"status": false
}
]
}
]
Počáteční část hledání je v podstatě
.find({
_id: '5e90ae0e0ed9974174e92826',
payments: { $elemMatch: { year_month: '2020_03' }}
})
Tomu neodpovídá nic, a protože je upsert nastaveno na true, fineOneAndUpdate se pokusí vytvořit zcela nový dokument. I kdyby byl schopen vytvořit pole z neodpovídajícího pozičního operátoru, dokument, který by se snažil přidat, by byl:
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_03",
"status": false
}
]
}
Toto není správné a vložení se nezdařilo z důvodu duplicitního _id
hodnotu.
Pokud používáte MongoDB 4.2, můžete použít agregační kanál jako druhý argument pro findAndUpdate
zkontrolujte pole prvku, který vás zajímá, a přidejte jej, pokud chybí.
Jedna nepříliš pěkná metoda je níže. FindOneAndUpdate bude odpovídat _id a kanál:
- zkontroluje, zda některý prvek v poli odpovídá požadovanému year_month
- Pokud ano, $redukujte pole a aktualizujte stavové pole v tomto prvku
- Pokud ne, přidejte nový prvek
- Přiřaďte výsledek zpět k payments
.findOneAndUpdate(
{ "_id": "5e90ae0e0ed9974174e92826" },
[{$set: {
payments: {$cond:[
{$gt:[
{$size:
{$filter:{
input:"$payments",
cond:{$eq:["$$this.year_month","2020_03"]}
}}},
1
]},
{$reduce:{
input:"$payments",
initialValue:[],
in:{$concatArrays:[
"$$value",
[{$cond:[
{$eq:["$$this.j",3]},
{$mergeObjects:["$$this",{status:true}]},
"$$this"
]}]
]}
}},
{$concatArrays:[
"$payments",
[{year_month:"2020_03", status:true}]
]}
]}
}}]
)