mongodb多文档更新(无事务)的最佳实践

时间:2019-12-21 08:00:32

标签: node.js mongodb nosql

我正在为我们的电子商务提供库存管理服务,因此决定尝试mongodb。在此服务中,我必须实现多文档更新。

我知道mongodb支持事务并且我尝试了,但是看起来非常不稳定。它偶尔会成功,但是大多数情况下会返回此错误:Transaction 1 has been committed.根据我的调查,解决方案基本上是添加重试逻辑,直到它起作用为止。我认为这不是一个好方法。平均而言,它需要重试10次,并且根据mongodb文档,与其他查询相比,事务处理成本更高。尽管“支持”交易,但mongodb还建议不要依赖交易。

最后,我决定使用服务器端锁定系统(异步锁定模块)来锁定相关库存,同时对其进行更新。现在,这解决了我最大的问题,并发问题。我希望通过使更新部分尽可能简单(除非服务器在进程中途停机)来使整个更新问题的原子性大大减少。但是,这仍然是一个问题。

我也不认为将锁锁定在服务器端是最佳实践。

所以我想知道是否存在正确的NoSQL方法来解决我的事务问题。

让我详细解释我的问题:

股票模式的核心部分看起来像这样(为了简单起见,我删除了一些与此问题无关的字段)

const StockSchema = new Schema({
  qty: { type: Number, required: true },
  logs: [
    {
      qty: { type: Number, required: true },
      order: { type: ObjectId, ref: 'order', required: true },
    }
  ]
});

下订单时,有些情况下qty必须从一个以上的stock文档中递减,因为单个库存不足qty

例如,假设一个产品有两个stock文档:

let stock1 = {
  qty: 3,
  logs: []
}

let stock2 = {
  qty: 5,
  logs: []
}

我们刚收到一个需要7个单位的订单。 因此,我们首先从stock1减少3个单位,从stock2减少剩余的4个单位。 结果应为:

let stock1 = {
  qty: 0,
  logs: [{ qty: 3, order: 'orderId' }]
};

let stock2 = {
  qty: 1,
  logs: [{ qty: 4, order: 'orderId' }]
};

这是我的代码:

let { qty } = order;
let stocks = await Stock.find({});
stocks= stocks.map(stock => {
  let change = 0;
  if (qty === 0) return stock;
  if (stock.qty >= qty) {
    change = qty;
    stock.qty -= qty;
    qty = 0;
  } else {
    change = stock.qty;
    qty -= stock.qty;
    stock.qty = 0;
  }
  stock.logs.push({ qty: change, order: orderId });
  return stock;
});
await Promise.all(stocks => stock.save()) //all the save occurs almost simultaneously, which is why Im expecting all or nothing issue is less of a problem.

0 个答案:

没有答案