По принцип имате 3 случая:
- и книгата, и рецензията съществуват. Това е прост
$set
- книгата съществува, но не и рецензията. Това изисква
$push
- книгата не съществува. Това изисква
{upsert:1}
и$setOnInsert
Не успях да намеря начин да обединя които и да е две от тях, без да компрометирам целостта на данните в случай на повреда (не забравяйте, че 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}
)
Можете сляпо да стартирате тези три актуализации в необработен вид, тъй като между тях няма припокриващи се регистри. Хубавото е, че всички тези операции са идемпотентни
. Така че можете да ги прилагате веднъж или няколко пъти и винаги да получавате същия резултат. Това е особено важно в случай на отказ. Освен това няма начин вашата база данни да бъде непоследователна или да загуби съществуващата данни в случай на повреда. В най-лошия случай прегледът не е актуализиран. Най-накрая това трябва гарантира съгласуваност на данните дори в случай на едновременни актуализации (т.е.:в този случай една актуализация ще замени другата, но не трябва да имате два документа за една и съща книга или две рецензии на един и същи потребител за една и съща книга).
Тази по-късна точка трябва да бъде потвърдена, тъй като тук е късно, така че анализът ми може да е малко съмнителен.
Като последна бележка, ако искате да намалите броя на двупосочните пътувания между MongoDB и вашето приложение, можете да погледнете update
команда за база данни
което ви позволява да обвиете няколко актуализации в една команда.