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

MongoDB多请求更新文档避免数据丢失解决方案咨询

解决MongoDB并发更新数据丢失问题

问题描述

当多个并发请求更新同一文档的数值字段时,会出现数据丢失的情况:

示例:daily_Usage初始值为0,两个请求同时读取到该值,各自加1后执行更新,最终daily_Usage结果为1,但预期应为2。

Users文档结构如下:

{
  name: "abc",
  place: "bangalore",
  userLimits: {
    daily: 10,
    daily_Usage: 0
  }
}

原代码问题分析

原代码采用先查询后更新的逻辑,这会引入竞态条件——多个请求同时读取到相同的字段值,各自计算后覆盖更新,导致部分更新丢失。原代码:

lists.map(async (list) => { 
  let userInfo = await Users.find({ name: "abc"});  // 假设仅一个用户,后续会改为动态获取
  let query = { name: userInfo[0].name}
  let update = { "userLimits.daily_Usage": userInfo[0].userLimits.daily_Usage + 1  }; 
  await Users.findOneAndUpdate(query, update)
}).catch(function (error) {
  console.log("Error");
});

解决方案

核心是使用MongoDB的$inc原子操作符,让数据库层面完成数值递增,消除客户端的竞态条件;同时正确处理map中的异步操作。

修改后的代码

// 用Promise.all等待所有异步更新完成
await Promise.all(lists.map(async (list) => { 
  // 直接通过$inc原子递增目标字段,无需先查询文档
  await Users.findOneAndUpdate(
    { name: "abc" },  // 查询条件,后续可改为动态值
    { $inc: { "userLimits.daily_Usage": 1 } },  // 原子性将daily_Usage加1
    { new: true }  // 可选配置:返回更新后的文档,不需要可省略
  );
})).catch(error => {
  console.log("更新出错:", error);
});

关键说明

  • $inc原子操作:MongoDB原生支持的操作,会在数据库端对指定字段执行原子递增,多个并发请求会被数据库排队处理,确保每个递增操作都生效,不会丢失更新。
  • Promise.all处理异步队列:map返回的是多个Promise组成的数组,Promise.all会等待所有更新操作完成,并且统一捕获错误,避免单个请求失败导致流程异常。
  • 移除先查询步骤:不需要先获取字段当前值,直接交给数据库处理原子递增,从根源上消除竞态条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:25:16