Je hebt in principe 3 gevallen:
- zowel het boek als de recensie bestaat. Dit is een eenvoudige
$set
- het boek bestaat, maar de recensie niet. Dit heeft een
$push
. nodig - het boek bestaat niet. Dit moet
{upsert:1}
en een$setOnInsert
Ik kon geen manier vinden om deze twee te verenigen zonder de gegevensintegriteit in gevaar te brengen in geval van een storing (onthoud dat MongoDB geen atomaire transactie heeft).
Dus mijn beste idee is het volgende:
// 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}
)
U kunt deze drie updates blindelings onbewerkt uitvoeren, omdat er geen overlappende casus tussen zit. Het mooie is dat al deze bewerkingen idempotent
zijn . Je kunt ze dus een of meerdere keren toepassen en altijd hetzelfde resultaat krijgen. Dit is vooral belangrijk in het geval van een failover. Bovendien kan uw DB op geen enkele manier inconsistent zijn of bestaande kwijtraken gegevens in geval van storing. In het slechtste geval is de recensie niet bijgewerkt. Ten slotte moet dit moeten garandeert consistentie van gegevens, zelfs in het geval van gelijktijdige updates (d.w.z.:in dat geval zal de ene update de andere overschrijven, maar u zou uiteindelijk niet twee documenten voor hetzelfde boek of twee recensies van dezelfde gebruiker voor hetzelfde boek moeten hebben).
Dat latere punt moet worden bevestigd omdat het hier laat is, dus mijn analyse kan enigszins twijfelachtig zijn.
Als laatste opmerking, als u het aantal retourvluchten tussen MongoDB en uw app wilt verminderen, kunt u een kijkje nemen op de update
database commando
zodat u meerdere updates in één opdracht kunt stoppen.