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

Mongoose异步批量更新用户积分问题及优化尝试

解决Mongoose异步更新积分丢失的问题

原问题核心原因

你碰到的是典型的异步竞态条件问题:原代码里用forEach遍历竞猜记录时,所有的用户查询和保存操作是并行触发的——多个请求同时读取到用户的初始积分,各自累加后再写回数据库,后面的写操作会覆盖前面的,最终就出现了4条记录只加2分的情况。

你的改写思路完全正确

改用async/await搭配for...of循环的方案完美解决了串行执行的需求:for...of会等待每一次循环里的所有异步操作完成后,再执行下一次循环。这样每处理一条竞猜记录时,读取到的用户数据都是上一次更新后的最新状态,从根源上避免了积分覆盖的问题。

代码小优化建议

不过看你的改写代码,有个冗余操作需要调整:你先查询用户并手动累加积分,随后又调用user.update用$inc原子操作更新,这两步其实重复了。推荐二选一,更推荐用原子更新($inc),因为它直接在数据库层面执行累加,即使有其他并发操作也能保证数据一致性:

// 替换你当前的user修改和update代码
await User.updateOne(
  { username: scheduleTip.username },
  {
    $inc: {
      "tippspiel.overallPoints": points,
      "tippspiel.seasonPoints": points,
      "tippspiel.gameWeekPoints": points
    }
  }
);

如果你想保留查询用户的逻辑,直接修改后save即可,无需再调用update:

if (user) {
  const winner = calculateWinner(schedule);
  const points = calculatePoints(scheduleTip, winner);
  user.tippspiel.overallPoints += points;
  user.tippspiel.seasonPoints += points;
  user.tippspiel.gameWeekPoints += points;
  await user.save(); // 直接保存修改后的文档
  logger.info("[Tippspiel-User]: User tippspiel points were updated.");
}

测试方案参考

为了确保代码稳定工作,你可以按以下步骤测试:

  • 创建一个测试用户,设置初始积分(比如overallPoints: 0)
  • 生成4条属于该用户的竞猜记录,其中几条设置为猜对结果(触发积分累加),几条设置为猜错(积分为0)
  • 调用updateUserPoints函数,传入对应的赛事schedule对象
  • 执行完成后查询该用户的积分,验证是否符合预期(比如3条猜对的话,积分应该是对应点数的3倍)
  • 额外测试平局、主胜、客胜三种结果的积分计算,确保calculateWinner和calculatePoints逻辑无误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:13:26