MongoDB 更新文档在 foreach 循环中失败

Posted

技术标签:

【中文标题】MongoDB 更新文档在 foreach 循环中失败【英文标题】:MongoDB updating the document fails in a foreach loop 【发布时间】:2021-05-31 20:04:05 【问题描述】:

我正在开发一个网站,我们在一个 JS 数组中获取每天的订单,如下所示:

let todayOrders = [
    
        order_name: "apple",
        order_count: 2
    ,
    
        order_name: "orange",
        order_count: 3
    ,
    
        order_name: "apple",
        order_count: 1
    
];

我需要将每个订单计数添加到跟踪每个订单的总订单计数文档中。所以我在其中使用了一个 foreach 循环和一个 updateOne 方法,如下所示:

todayOrders.forEach(function(item, index)
    Product.updateOne(
        
            product_name: item.order_name
        ,
        
            $inc: product_count: item1.order_count
        ,
    );
);

问题是这段代码只有在todayOrders 不包含任何重复的order_name 时才能正常工作,在这种情况下它不会应用所有更改。我认为这与 Mongoose 的 async 行为有关。

【问题讨论】:

item1 应该是 item。 跟踪“总”订单需要 $inc 而不是 $set 是的。我对那个不好。 【参考方案1】:

您不是在等待您的承诺得到解决,这被认为是可能导致意外行为的不良做法,在您的情况下,它不应该影响预期的逻辑,因为单个文档上的 Mongo 写入运算符是原子的。

但是我仍然建议您重构代码以等待承诺解决,这不能使用 forEach 完成,因为它没有返回值。

这里有一个简单的例子来说明如何做到这一点:

for (const item of todayOrders) 
    await Product.updateOne(
        
            product_name: item.order_name
        ,
        
            $inc: product_count: item1.order_count
        ,
    );

或者


// ### This is not recommended as it not limited by scale and can cause the app to run out of memory and crash ###


const promises = [];
todayOrders.forEach(function(item, index)
    promises.push(Product.updateOne(
        
            product_name: item.order_name
        ,
        
            $inc: product_count: item.order_count
        ,
    ))
);
await Promise.all(promises)

对于并行运行,我建议您使用 bluebird 之类的东西,但是您可以使用 js 原生 Promise 自己完成。

【讨论】:

【参考方案2】:

也许对订单进行分组。

todayOrders.reduce((acc,item)=>
  const index = acc.map(i=>i.order_name).indexOf(item.order_name);
  if(index === -1)
    acc.push(item);
  else 
    acc[index].order_count += item.order_count;
  return acc;
,[]).forEach(...)

【讨论】:

以上是关于MongoDB 更新文档在 foreach 循环中失败的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Node.js 在 MongoDB 中使用 cursor.forEach()?

如何使用 Node.js 在 MongoDB 中使用 cursor.forEach()?

猫鼬forEach循环并一一更新文档

在没有 for 循环的情况下更新多个文档 MongoDB

在 MongoDB 中更新具有不同 id 的多个文档

运行MongoDB查询以更新循环中的序列字段