【问题标题】:MongoDB, set a property by calculating other propertiesMongoDB,通过计算其他属性来设置一个属性
【发布时间】:2021-12-04 20:26:10
【问题描述】:

所以,我正在考虑像这样实现games 属性,

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

我想在每次添加游戏输赢数据时修改游戏比率。例如,如果在上面的例子中,如果玩家赢得另一场比赛,那么操作将是 ,

  1. 增加赢得 1
  2. 增加播放 1
  3. winRatio = 100 * 赢得/已玩

所以,{ $inc: { won: 1, played 1 } } 和其他一些东西。 那么,我该怎么做呢?一个明显的答案是获取数据,进行计算和发送数据。但我不想这样做。我想通过 MongoDB 方法和运算符来做到这一点。有可能吗?

【问题讨论】:

    标签: node.js mongodb mongodb-nodejs-driver


    【解决方案1】:

    查询

    • 管道更新需要 MongoDB >= 4.2(我们需要它来完成 1 个查询)
    • 用js变量代替-2来保存游戏结果
      • 如果赢 1 则放 1
      • 如果输了 2 put -2 etc(负数表示输了)
    • 如果数字 >0 则更新获胜,否则保留旧值
    • 如果数字为
    • 然后在第二个 $set 更新 winRation,基于之前计算的值。

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

    编辑

    您可以简化查询并检查您的驱动程序, 另外,如果您知道游戏始终是 1 赢或输,您可以在驱动程序上编写类似 belloq 的内容(您也可以在没有 if/else 的情况下编写变量,并在 games.won 或 games.lost 上编写 js 变量)

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

    【讨论】:

    • 这份工作是不是有点太复杂了? games.won 或 games.lot 一次不会增加超过 1。两者也不会同时增加。仅当玩家完成游戏后才需要更改此值。由于 games.played 也不能减少,因此不需要错误检查机制。
    • 所以,基本上是我一次要求的三个操作。
    • 如果您检查驱动程序会很简单,如果游戏总是一个,我会更新答案
    • 另外我有点好奇你为什么不使用$inc: { property: 1 }而不是$set: { property: { $add: ['property', 1] } }
    • 因为$inc 是一个更新操作符,而这里是使用管道更新,所以我们只能使用聚合操作符(我们没有$inc 聚合操作符)。 winRatio 让我们使用管道更新,因为它希望根据新值进行更新,所以我们需要 2 个阶段。在正常更新不够的情况下,我们会进行管道更新,我们可以在其中使用所有聚合运算符
    猜你喜欢
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 2018-03-26
    • 2018-05-12
    • 1970-01-01
    • 2010-12-08
    相关资源
    最近更新 更多