touhidurrr
touhidurrr

Reputation: 450

MongoDB, set a property by calculating other properties

So, I am thinking of implementing a games property like this,

{
  games: {
    won: 2,
    lost: 3,
    played: 5,
    winRatio: 40
  }
}

I want to modify game ratio each time I add a games win / lose data. For example if in above example if the player wins another game, then the operations would be ,

  1. increment won by 1
  2. increment played by 1
  3. winRatio = 100 * won / played

So, { $inc: { won: 1, played 1 } } and some other stuff. So, how do I do it? One obvious answer is fetch data, doing calculation and sending data. But I don’t want to do it. I want to do this by the MongoDB methods and operators. Is it possible?

Upvotes: 1

Views: 322

Answers (1)

Takis
Takis

Reputation: 8705

Query

  • pipeline update requires MongoDB >= 4.2 (we need it to do it with 1 query)
  • instead of -2 put the js variable to hold the result of game
    • if win 1 put 1
    • if lost 2 put -2 etc (negative means lost)
  • updates won if number is >0 else keep old value
  • updates lost if number is <0 (adds the abs value to lost) else keep old value
  • and then in second $set updates the winRation, based on previously calculated values.

Test code here

update(
{},
[{"$set": 
    {"games.won": 
      {"$cond": 
        [{"$gt": [-2, 0]}, {"$add": ["$games.won", -2]}, "$games.won"]},
     "games.lost": 
      {"$cond": 
        [{"$lt": [-2, 0]}, {"$add": ["$games.lost", {"$abs": -2}]},
          "$games.lost"]},
     "games.played": {"$add": ["$games.played", {"$abs": -2}]}}},
  {"$set": 
    {"games.winRatio":  
      {"$multiply": [100, {"$divide": ["$games.won", "$games.played"]}]}}}])

Edit

You can make the query simpler and do the check on your driver also, also if you know that the game is always 1 won or lost you can write something like the belloq on your driver (you can also have a variable and write it without if/else, js variable on games.won or games.lost)

if(won)

update(
{},
[{"$set": 
    {"games.won": {"$add": ["$games.won", 1]},
      "games.played": {"$add": ["$games.played", 1]}}},
  {"$set": 
    {"games.winRatio": 
      {"$multiply": [100, {"$divide": ["$games.won", "$games.played"]}]}}}])

else

update(
{},
[{"$set": 
    {"games.lost": {"$add": ["$games.lost", 1]},
      "games.played": {"$add": ["$games.played", 1]}}},
  {"$set": 
    {"games.winRatio": 
      {"$multiply": [100, {"$divide": ["$games.won", "$games.played"]}]}}}])

Upvotes: 1

Related Questions