Het grootste probleem is dat findOneAndUpdate
doet precies wat de naam doet vermoeden. Het voert een find
uit met behulp van het meegeleverde filter, en als er een overeenkomst wordt gevonden, worden de updates toegepast op het eerste overeenkomende document.
Als de collectie alleen dit document bevat:
[
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_02",
"status": false
}
]
}
]
Het eerste vondstgedeelte is in wezen
.find({
_id: '5e90ae0e0ed9974174e92826',
payments: { $elemMatch: { year_month: '2020_03' }}
})
Dit komt met niets overeen, en aangezien upsert is ingesteld op true, probeert fineOneAndUpdate een gloednieuw document te maken. Zelfs als het een array zou kunnen maken van een ongeëvenaarde positionele operator, zou het document dat het zou proberen toe te voegen zijn:
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_03",
"status": false
}
]
}
Dit is niet correct en kan niet worden ingevoegd vanwege dubbele _id
waarde toch.
Als u MongoDB 4.2 gebruikt, kunt u een aggregatiepijplijn gebruiken als tweede argument voor findAndUpdate
om de array te controleren op het element waarin u geïnteresseerd bent en het toe te voegen als het ontbreekt.
Een niet erg mooie methode is hieronder. De findOneAndUpdate komt overeen met de _id en de pijplijn zal:
- controleren of een element in de array overeenkomt met de gewenste year_month
- Zo ja, $reduceer de array om het statusveld in dat element bij te werken
- Zo niet, voeg dan een nieuw element toe
- Wijs het resultaat toe aan 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}]
]}
]}
}}]
)