decrement value in collection until 0
Meteor.users.update({'profile.score': {$gte: 10}}, {$inc: {'profile.score': -10}}, {multi: true});
Does this accomplish what you need? Change selector as needed.
Explanation: We filter out users who have a score of 10 or more. We "increase" all of the matching users' scores by -10 (so we decrease them by 10).
The basic process here is to use the $inc
update operator, but of course there is the governance of 0
as a floor value. So you can therefore either accept:
Users.update({ "_id": userId },{ "$inc": { "score": -10 } });
Users.update(
{ "_id": userId, "score": { "$lt": 0 } },
{ "$set": { "score": 0 } }
);
As "two" operations and connections as shown. Or you can get fancier in Meteor methods with the Bulk Operations API of MongoDB:
Meteor.methods(
"alterUserScore": function(userId,amount) {
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var bulk = db.collection('users').inititializeOrderedBulkOp();
bulk.find({ "_id": userId }).updateOne({ "$inc": { "score": amount } });
bulk.find({ "_id": userId, "score": { "$lt": 0 } }).updateOne({
"$set": { "score": 0 }
});
bulk.execute(
Meteor.bindEnvironment(
function(err,result) {
// maybe do something here
},
function(error) {
// report real bad here
}
)
);
}
);
The advantage there on the "server" request is that even though it is still "two" update operations, the actual request and response from the server is only "one" request and "one" response. So this is a lot more efficient than two round trips. Especially if intitiated from the browser client.
If you did otherwise, then you likely miss things such as when the current value is 6
and you want to decrease that to 0
. A $gt
in the condition will fail there.