MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

mangusto atualizar array ou adicionar ao array


O principal problema é que findOneAndUpdate faz exatamente o que o nome indica. Ele executa um find usando o filtro fornecido e, se uma correspondência for encontrada, aplica as atualizações ao primeiro documento correspondente.

Se a coleção contiver apenas este documento:
[
    {
        "_id": "5e90ae0e0ed9974174e92826",
        "payments": [
            {
                "year_month": "2020_02",
                "status": false
            }
        ]
    }
]

A parte inicial de busca é essencialmente
.find({
        _id: '5e90ae0e0ed9974174e92826',
        payments: { $elemMatch: { year_month: '2020_03' }}
})

Isso não corresponde a nada e, como upsert está definido como true, fineOneAndUpdate tenta criar um novo documento. Mesmo se fosse capaz de criar um array a partir de um operador posicional sem correspondência, o documento que estaria tentando adicionar seria:
 {
        "_id": "5e90ae0e0ed9974174e92826",
        "payments": [
            {
                "year_month": "2020_03",
                "status": false
            }
        ]
}

Isso não está correto e não seria inserido devido a _id duplicado valor de qualquer maneira.

Se você estiver usando o MongoDB 4.2, poderá usar um pipeline de agregação como segundo argumento para findAndUpdate para verificar a matriz do elemento em que você está interessado e adicioná-lo se estiver faltando.

Um método não muito bonito está abaixo. O findOneAndUpdate corresponderá ao _id, e o pipeline irá:
- verificar se algum elemento na matriz corresponde ao ano_mês desejado
- Se sim, $reduza a matriz para atualizar o campo de status nesse elemento
/>- Caso contrário, anexe um novo elemento
- Atribua o resultado de volta a 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}]
                  ]}
          ]}
     }}]
)