sql >> Databasteknik >  >> NoSQL >> MongoDB

mongoose uppdatera array eller lägg till i arrayen

Det största problemet är att findOneAndUpdate gör precis vad namnet antyder. Den kör en find med det medföljande filtret, och om en matchning hittas, tillämpar uppdateringarna på det första matchande dokumentet.

Om samlingen endast innehåller detta dokument:

[
    {
        "_id": "5e90ae0e0ed9974174e92826",
        "payments": [
            {
                "year_month": "2020_02",
                "status": false
            }
        ]
    }
]

Den första sökdelen är i huvudsak

.find({
        _id: '5e90ae0e0ed9974174e92826',
        payments: { $elemMatch: { year_month: '2020_03' }}
})

Detta matchar ingenting, och eftersom upsert är satt till sant, försöker fineOneAndUpdate skapa ett helt nytt dokument. Även om den skulle kunna skapa en array från en oöverträffad positionsoperator, skulle dokumentet som den skulle försöka lägga till vara:

 {
        "_id": "5e90ae0e0ed9974174e92826",
        "payments": [
            {
                "year_month": "2020_03",
                "status": false
            }
        ]
}

Detta är inte korrekt och skulle misslyckas att infogas på grund av dubblett av _id värde ändå.

Om du använder MongoDB 4.2 kan du använda en aggregeringspipeline som det andra argumentet för att findAndUpdate för att kontrollera arrayen för det element du är intresserad av och lägga till det om det saknas.

En inte särskilt vacker metod är nedan. FindOneAndUpdate kommer att matcha _id, och pipeline kommer:
- kontrollera om något element i arrayen matchar önskad year_month
- Om så är fallet, $reducera arrayen för att uppdatera statusfältet i det elementet
- Om inte, lägg till ett nytt element
- Tilldela resultatet tillbaka till 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}]
                  ]}
          ]}
     }}]
)


  1. mongodb unwind array kapslad inuti en array av dokument

  2. Hitta dokument med matriser som innehåller ett dokument med ett visst fält

  3. Hur man bygger en rekursiv struktur med MongoDB

  4. Mongoose går med i två samlingar och får bara specifika fält från den sammanslagna samlingen