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