Masalah utamanya adalah findOneAndUpdate
melakukan persis seperti namanya. Itu mengeksekusi find
menggunakan filter yang disediakan, dan jika kecocokan ditemukan, menerapkan pembaruan ke dokumen pertama yang cocok.
Jika koleksi hanya berisi dokumen ini:
[
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_02",
"status": false
}
]
}
]
Bagian find awal pada dasarnya adalah
.find({
_id: '5e90ae0e0ed9974174e92826',
payments: { $elemMatch: { year_month: '2020_03' }}
})
Ini tidak cocok, dan karena upsert disetel ke true, fineOneAndUpdate mencoba membuat dokumen baru. Bahkan jika ia dapat membuat larik dari operator posisi yang tidak cocok, dokumen yang akan coba ditambahkan adalah:
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_03",
"status": false
}
]
}
Ini tidak benar, dan akan gagal dimasukkan karena duplikat _id
tetap bernilai.
Jika Anda menggunakan MongoDB 4.2, Anda dapat menggunakan pipa agregasi sebagai argumen kedua untuk findAndUpdate
untuk memeriksa larik untuk elemen yang Anda minati dan menambahkannya jika tidak ada.
Salah satu metode yang tidak terlalu cantik ada di bawah ini. findOneAndUpdate akan cocok dengan _id, dan pipeline akan:
- memeriksa apakah ada elemen dalam array yang cocok dengan year_month yang diinginkan
- Jika demikian, $reduce array untuk memperbarui kolom status di elemen tersebut
- Jika tidak, tambahkan elemen baru
- Tetapkan kembali hasilnya ke 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}]
]}
]}
}}]
)