基本的に3つのケースがあります:
- 本とレビューの両方が存在します。これは単純な<code>$set
- 本は存在しますが、レビューはありません。これには
$push
が必要です - 本は存在しません。これには
{upsert:1}
が必要です および$setOnInsert
障害が発生した場合にデータの整合性を損なうことなく、これらの2つを統合する方法を見つけることができませんでした(MongoDBにはアトミックトランザクションがないことを忘れないでください)。
だから私の 最良のアイデアは次のとおりです:
// Case 1:
db.books.update({isbn:'1234567890',
review: { $elemMatch: {userID: '01234'}}},
{$set: {'review.$.rating': NEW_RATING}}
)
// Case 2:
db.books.update({isbn:'1234567890',
review: { $not: { $elemMatch: {userID: '01234'}}}},
{$push: {review: {rating: NEW_RATING, userID:'01234'}}}
)
// Case 3:
db.books.update({isbn:'1234567890'},
{$setOnInsert: {review: [{rating: NEW_RATING, userID:'01234'}]}},
{upsert:1}
)
これらの3つの更新は、重複するケースがないため、生で盲目的に実行できます。すばらしいのは、これらすべての操作がべき等
であるということです。 。したがって、それらを1回または数回適用して、常に同じ結果を得ることができます。これは、フェイルオーバーの場合に特に重要です。さらに、DBに一貫性がなくなったり、既存のが失われたりすることはありません。 障害が発生した場合のデータ。最悪の場合、レビューはではありません 更新しました。最後に、これはすべき 同時更新の場合でもデータの一貫性を保証します(つまり、その場合、一方の更新でもう一方の更新が上書きされますが、同じ本の2つのドキュメント、または同じ本の同じユーザーの2つのレビューになることはありません)。
ここでは遅いので、後で確認する必要があるので、私の分析はやや疑わしいかもしれません。
最後に、MongoDBとアプリ間のラウンドトリップ数を減らしたい場合は、 update
データベースコマンド
1つのコマンドで複数の更新をラップできます。