MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Mongoose Array aktualisieren oder zum Array hinzufügen

Das Hauptproblem ist, dass findOneAndUpdate macht genau das, was der Name verspricht. Es führt ein find aus Verwenden Sie den bereitgestellten Filter und wenden Sie die Aktualisierungen auf das erste übereinstimmende Dokument an, wenn eine Übereinstimmung gefunden wird.

Wenn die Sammlung nur dieses Dokument enthält:

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

Der anfängliche Suchteil ist im Wesentlichen

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

Dies passt zu nichts, und da upsert auf true gesetzt ist, versucht fineOneAndUpdate, ein brandneues Dokument zu erstellen. Selbst wenn es in der Lage wäre, ein Array aus einem nicht übereinstimmenden Positionsoperator zu erstellen, würde das Dokument, das es hinzuzufügen versucht, folgendes sein:

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

Dies ist nicht korrekt und würde aufgrund doppelter _id nicht eingefügt werden Wert sowieso.

Wenn Sie MongoDB 4.2 verwenden, können Sie eine Aggregationspipeline als zweites Argument für findAndUpdate verwenden um das Array auf das Element zu überprüfen, an dem Sie interessiert sind, und es hinzuzufügen, falls es fehlt.

Eine nicht sehr schöne Methode ist unten. findOneAndUpdate stimmt mit der _id überein, und die Pipeline wird:
- prüfen, ob irgendein Element im Array mit dem gewünschten Jahr_Monat übereinstimmt
- Wenn ja, $reduzieren Sie das Array, um das Statusfeld in diesem Element zu aktualisieren
- Wenn nicht, fügen Sie ein neues Element hinzu
- Weisen Sie das Ergebnis wieder payments zu

.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}]
                  ]}
          ]}
     }}]
)