node.jsmongodbmongodb-nodejs-driver

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?


Solution

  • Query

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