2013-10-08 4 views
1

J'ai le schéma suivant ci-dessous et j'ai besoin de faire une mise à jour qui est détaillée ci-dessous. Je ne sais pas comment s'y prendre.mise à jour conditionnelle dans mongodb

UserPromo = new Schema 
    sendFBInvite: 
    earnedIntros: 
     type: Number 
     default: 0 
    earningActionCounter: 
     type: Number 
     default: 0 
    actions: 
     type: Number 
     default:1 
    earnings: 
    earnedIntros: 
     type: Number 
     default: 0 
    usedIntros: 
     type: Number 
     default: 0 

chaque fois que sendFBInvite.earningActionCounter va à 5 Je veux sendFBInvite.earnedIntros pour incrémenter et earnings.earnedIntros à incrémenter 1. En même temps, je veux réinitialiser sendFBInvite.earningActionCounter à 0

est-il un moyen de le faire en un seul appel? Merci d'avance pour votre aide!

Répondre

1

NO. Le cœur de MongoDB est d'avoir toute la logique métier au niveau de l'application et non la base de données. Bref, je ne pense pas que ce soit possible. Note de côté: MongoDB est très rapide et vous pouvez exécuter plusieurs requêtes select/find, puis déclencher et mettre à jour. De plus, il existe également une commande findAndModify (http://docs.mongodb.org/manual/reference/command/findAndModify/) qui pourrait vous intéresser.

+1

Vous avez raison, j'ai essayé plusieurs choses différentes. J'essayais d'éviter le scénario où un utilisateur est connecté à deux machines et fait la même action résultant des mêmes revenus. Dans ce scénario, je pourrais avoir une situation avec des gains correctement mesurés. Cela étant dit, le cas d'utilisation n'est pas quelque chose dont je dois me préoccuper pour le moment. Merci d'avoir répondu! – Hans

0

c'est vieux, mais pour les autres qui arrivent ici ... la réponse précédente mentionnait avoir besoin de faire cela dans la couche application, ce qui est correct. Voici un exemple pseudo-code de la façon dont vous pouvez en toute sécurité et effectuer efficacement une telle mise à jour:

incrementActionCounter() { 
    do { 
     var tryagain = false 
     // do the common action first, but only if it would not reach 
     // the boundary condition (5) 
     err = collection("").update(
      {"sendFBInvite.earnedActionCounter": {$ne: 4}}, 
      {$inc:{"sendFBInvite.earnedActionCounter": 1}} 
     ) 
     // 'not found' means that it's likely already at 4... so... 
     if err == "not found" { 
      // still need a condition here, in case someone else updated 
      // the value behind our back 
      err = collection("").update({"sendFBInvite.earnedActionCounter": 4}, { 
       $inc: { 
        "sendFBInvite.earnedIntros":1, 
        "earnings.earnedIntros":1 
       }, 
       $set:{ 
        "sendFBInvite.earnedActionCounter": 0 
       } 
      }) 
      // 'not found' here means something changed between our 2 queries 
      if err == "not found" { 
       tryagain = true; 
      } else if isSomeOtherError(err) { 
       return err 
      } 
     } 
    } while(tryagain) 
} 

évidemment, en fonction de vos besoins, vous pouvez limiter la nouvelle tentative et juste retourner une erreur si la séquence échoue, mais quelque chose comme ce qui précède devrait résoudre le problème sans produire de nouveaux cas de bordure.