Hans
Hans

Reputation: 1055

conditional update in mongodb

I have the following schema below and need do an update which is detailed below. Not sure how to go about it.

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

everytime sendFBInvite.earningActionCounter goes to 5 I want sendFBInvite.earnedIntros to increment and earnings.earnedIntros to increment by 1. At the same time I want to reset sendFBInvite.earningActionCounter to 0

Is there a way to do this in one call? thanks in advance for your help!

Upvotes: 2

Views: 5724

Answers (2)

J. Paulding
J. Paulding

Reputation: 504

this is old, but for others getting here... the earlier answer mentioned needing to do this in the application layer, which is correct. here's a pseudo-code example of how you might safely and efficiently perform such an update:

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)
}

obviously, depending on your needs, you could limit the retry and just return an error if the sequence fails, but something like the above should solve the problem w/o producing new edge cases.

Upvotes: 0

rohit kotian
rohit kotian

Reputation: 130

NO. The core of MongoDB is to have all the business logic in the application level and not DB. So in short I don't think its possible.

Side note: MongoDB is very fast and you can run multiple select/ find queries and then fire and update. Plus there is also findAndModify command (http://docs.mongodb.org/manual/reference/command/findAndModify/) by which might be good for you to look into.

Upvotes: 1

Related Questions