Du har som udgangspunkt 3 tilfælde:
- både bogen og anmeldelsen findes. Dette er et simpelt
$set
- bogen findes, men ikke anmeldelsen. Dette kræver en
$push
- bogen findes ikke. Dette har brug for
{upsert:1}
og en$setOnInsert
Jeg var ikke i stand til at finde en måde at forene to af disse uden at kompromittere dataintegriteten i tilfælde af fejl (husk at MongoDB ikke har atomtransaktion).
Så min bedste idé er følgende:
// 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}
)
Du kan blindt køre disse tre opdateringer i en rå, da der ikke er nogen overlappende sag mellem dem. Det smukke ved sagen er, at alle disse operationer er idempotente
. Så du kan anvende dem én eller flere gange og altid få det samme resultat. Dette er især vigtigt i tilfælde af failover. Derudover er der ingen måde for din DB at være inkonsekvent eller miste eksisterende data i tilfælde af fejl. I værste fald er anmeldelsen ikke opdateret. Endelig bør dette garantere datakonsistens selv i tilfælde af samtidige opdateringer (dvs.:i så fald vil den ene opdatering overskrive den anden, men du bør ikke ende med at have to dokumenter for den samme bog eller to anmeldelser af den samme bruger for den samme bog).
Det senere punkt skal bekræftes, da det er sent her, så min analyse kan være noget tvivlsom.
Som sidste bemærkning, hvis du ønsker at reducere antallet af rundrejser mellem MongoDB og din app, kan du tage et kig på update
databasekommando
giver dig mulighed for at samle flere opdateringer i én kommando.