2012-02-24 1 views
0

J'imagine foo est en train de faire le point sur le troisième commentaire, comments.2.value, tandis que bar est $pull -ing, en supprimant le premier commentaire.mongo mettant à jour l'élément de tableau et la condition de course?

Si foo finit en premier, le troisième commentaire est mis à jour avec succès, car l'index est toujours correct.

Mais si bar se termine d'abord, puis l'indice a changé, et foo « s comments.2.value affecterait pas le troisième commentaire plus.

Ce scénario est-il possible, et si c'est le cas, je me demande s'il existe des solutions communes pour les mises à jour d'éléments de tableau et les conditions de course?

Merci!

Répondre

3

La situation que vous avez décrite est théoriquement possible si plusieurs applications accèdent à la base de données simultanément. Pour cette raison, il est préférable, si possible, de donner à chaque membre du tableau un identifiant unique, plutôt que d'accéder aux éléments du tableau par position.

Par exemple,

> db.myComments.save({_id:1, 
comments:[ 
{cid:1, author:"Marc", comment:"Marc's Comment"}, 
{cid:2, author:"Mike", comment:"Mike's Comment"}, 
{cid:3, author:"Barrie", comment:"Barrie's Comment"} 
]}) 

Si nous voulons modifier le commentaire de Mike, mais nous ne savons pas nécessairement qu'il apparaît deuxième dans le tableau, nous pouvons le mettre à jour comme ceci:

> db.myComments.update({_id:1, "comments.cid":2}, {$set:{"comments.$.comment":"Mike's NEW Comment"}}) 
> db.myComments.find().pretty() 
{ 
    "_id" : 1, 
    "comments" : [ 
     { 
      "cid" : 1, 
      "author" : "Marc", 
      "comment" : "Marc's Comment" 
     }, 
     { 
      "author" : "Mike", 
      "cid" : 2, 
      "comment" : "Mike's NEW Comment" 
     }, 
     { 
      "cid" : 3, 
      "author" : "Barrie", 
      "comment" : "Barrie's Comment" 
     } 
    ] 
} 

On pourrait même changer l'ensemble du sous-document comme ceci:

> db.myComments.update({_id:1, "comments.cid":2}, {$set:{"comments.$":{cid:4, author:"someone else", comment:"A completely new comment!"}}}) 
> db.myComments.find().pretty() 
{ 
    "_id" : 1, 
    "comments" : [ 
     { 
      "cid" : 1, 
      "author" : "Marc", 
      "comment" : "Marc's Comment" 
     }, 
     { 
      "cid" : 4, 
      "author" : "someone else", 
      "comment" : "A completely new comment!" 
     }, 
     { 
      "cid" : 3, 
      "author" : "Barrie", 
      "comment" : "Barrie's Comment" 
     } 
    ] 
} 

le document de requête wil Je trouve la première valeur dans le tableau qui correspond, et le "$" dans le document de mise à jour fait référence à cette position.

Vous trouverez plus d'informations sur l'opérateur "$" dans la section "L'opérateur $ positional" de la documentation "Updating". J'espère que cela vous donnera une idée de la façon dont votre application peut modifier les valeurs d'un tableau sans faire référence à leur position. Bonne chance!

+0

Incroyable! Maintenant, je peux vraiment bien dormir une fois de plus. Je me demande ce que vous entendez par «théoriquement possible si plusieurs applications accèdent à la base de données simultanément», puisque dans mon cas je n'ai qu'une seule application, mais avec plusieurs utilisateurs simultanés. – bertie