You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Aggregate管道更新数组内对象并计算总和的实现方案

MongoDB聚合管道实现玩家生命值更新与总生命值计算

现有文档结构

// Game 集合文档
{
  number: "001",
  players: [
    { 
      _id: ObjectId("123"),
      lives: 0
    },
    { 
      _id: ObjectId("124"),
      lives: 2
    },
    { 
      _id: ObjectId("125"),
      lives: 3
    }
  ],
  totalLives: 5
}

需求

  • 根据number定位目标游戏,更新指定玩家(示例中_id=123)的lives字段
  • 同步更新该游戏的totalLives为所有玩家lives的总和

尝试的代码(存在问题)

原尝试用updateOne直接更新,但$sum无法在普通更新的$set中使用,代码如下:

await Games.updateOne(
  {
    number: game.number,
    "player._id": new ObjectId(newPlayer._id),
  },
  {
    $set: {
      "players.$[player].lives": newPlayer.lives,
      totalLives: { $sum: "$players.lives" },
    },
  },
  {
    arrayFilters: [{ "player._id": new ObjectId(newPlayer._id) }],
  }
)

正确实现方案(聚合管道式更新)

MongoDB 4.2及以上版本支持用聚合管道作为更新操作的内容,可先修改玩家生命值,再计算总生命值:

await Games.updateOne(
  // 匹配条件:定位指定number的游戏
  { number: game.number },
  // 聚合管道更新逻辑
  [
    // 第一步:更新指定玩家的lives字段
    {
      $set: {
        players: {
          $map: {
            input: "$players",
            as: "p",
            in: {
              $cond: [
                { $eq: ["$$p._id", new ObjectId(newPlayer._id)] },
                { ..."$$p", lives: newPlayer.lives }, // 替换目标玩家的lives
                "$$p" // 其他玩家保持原样
              ]
            }
          }
        }
      }
    },
    // 第二步:计算所有玩家lives的总和,更新totalLives
    {
      $set: {
        totalLives: { $sum: "$players.lives" }
      }
    }
  ]
)

代码说明

  1. 匹配阶段:仅通过number定位目标游戏即可,玩家匹配逻辑放在聚合管道内处理
  2. $map更新玩家:遍历players数组,通过$cond判断当前玩家ID是否为目标ID,是则替换lives值,否则保留原数据
  3. 计算总生命值:利用$sum直接对更新后的players.lives数组求和,赋值给totalLives

内容的提问来源于stack exchange,提问作者AES

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:15:51