Anda pada dasarnya memiliki 3 kasus:
- baik buku maupun resensinya ada. Ini adalah
$set
simple sederhana - buku itu ada tapi bukan resensinya. Ini membutuhkan
$push
- buku itu tidak ada. Ini membutuhkan
{upsert:1}
dan$setOnInsert
Saya tidak dapat menemukan cara untuk menyatukan keduanya tanpa mengorbankan integritas data jika terjadi kegagalan (ingat bahwa MongoDB tidak memiliki transaksi atomik).
Jadi saya ide terbaik adalah sebagai berikut:
// 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}
)
Anda dapat secara membabi buta menjalankan ketiga pembaruan tersebut secara mentah karena tidak ada kasus yang tumpang tindih di antara mereka. Yang menarik adalah semua operasi ini idempoten
. Jadi Anda bisa menerapkannya sekali atau beberapa kali dan selalu mendapatkan hasil yang sama. Hal ini sangat penting dalam kasus failover. Selain itu, tidak mungkin DB Anda tidak konsisten atau kehilangan yang ada data jika terjadi kegagalan. Paling buruk, ulasannya tidak diperbarui. Akhirnya ini harus menjamin konsistensi data bahkan dalam kasus pembaruan bersamaan (yaitu:dalam hal itu, satu pembaruan akan menimpa yang lain, tetapi Anda tidak harus memiliki dua dokumen untuk buku yang sama atau dua ulasan dari pengguna yang sama untuk buku yang sama).
Poin selanjutnya harus dikonfirmasi karena ini sudah larut malam sehingga analisis saya mungkin agak meragukan.
Sebagai catatan terakhir, jika Anda ingin mengurangi jumlah perjalanan pulang pergi antara MongoDB dan aplikasi Anda, Anda dapat melihat update
perintah basis data
memungkinkan Anda untuk menggabungkan beberapa pembaruan dalam satu perintah.