主な問題は、findOneAndUpdate
その名前が意味することを正確に行います。 find
を実行します 提供されたフィルターを使用し、一致するものが見つかった場合は、最初に一致したドキュメントに更新を適用します。
コレクションにこのドキュメントのみが含まれている場合:
[
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_02",
"status": false
}
]
}
]
最初の検索部分は基本的に
です.find({
_id: '5e90ae0e0ed9974174e92826',
payments: { $elemMatch: { year_month: '2020_03' }}
})
これは何にも一致しません。upsertがtrueに設定されているため、fineOneAndUpdateは新しいドキュメントを作成しようとします。一致しない位置演算子から配列を作成できたとしても、追加しようとしているドキュメントは次のようになります。
{
"_id": "5e90ae0e0ed9974174e92826",
"payments": [
{
"year_month": "2020_03",
"status": false
}
]
}
これは正しくなく、_id
が重複しているため挿入に失敗します とにかく価値があります。
MongoDB 4.2を使用している場合は、findAndUpdate
の2番目の引数として集計パイプラインを使用できます。 目的の要素の配列を確認し、欠落している場合は追加します。
あまりきれいではない方法の1つを以下に示します。 findOneAndUpdateは_idと一致し、パイプラインは次のようになります。
-配列内のいずれかの要素が目的のyear_monthと一致するかどうかを確認します
-一致する場合は、配列を$ reduceして、その要素のステータスフィールドを更新します
-そうでない場合は、新しい要素を追加します
-結果を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}]
]}
]}
}}]
)