Vous avez essentiellement 3 cas :
- le livre et la critique existent. Ceci est un simple
$set
- le livre existe mais pas la critique. Cela nécessite un
$push
- le livre n'existe pas. Cela nécessite
{upsert:1}
et un$setOnInsert
Je n'ai pas été en mesure de trouver un moyen d'unifier deux d'entre eux sans compromettre l'intégrité des données en cas d'échec (rappelez-vous que MongoDB n'a pas de transaction atomique).
Alors mon la meilleure idée est la suivante :
// 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}
)
Vous pouvez exécuter aveuglément ces trois mises à jour dans un raw car il n'y a pas de cas de chevauchement entre eux. La beauté de la chose est que toutes ces opérations sont idempotent
. Vous pouvez donc les appliquer une ou plusieurs fois et obtenir toujours le même résultat. Ceci est particulièrement important en cas de basculement. De plus, il n'y a aucun moyen pour votre base de données d'être incohérente ou de perdre l'existant données en cas de panne. Au pire, la critique n'est pas actualisé. Enfin, cela devrait garantir la cohérence des données même en cas de mises à jour simultanées (c'est-à-dire :dans ce cas, une mise à jour écrasera l'autre, mais vous ne devriez pas vous retrouver avec deux documents pour le même livre ou deux critiques du même utilisateur pour le même livre).
Ce dernier point doit être confirmé car il est tard ici, donc mon analyse pourrait être quelque peu douteuse.
Enfin, si vous souhaitez réduire le nombre d'allers-retours entre MongoDB et votre application, vous pouvez consulter le update
commande de base de données
vous permettant d'encapsuler plusieurs mises à jour en une seule commande.