【问题标题】:Mongoose/Mongodb, update each doc query, very slowMongoose/Mongodb,更新每个文档查询,很慢
【发布时间】:2020-12-04 01:21:52
【问题描述】:

我在猫鼬中有这个更新查询。它有 1600 个帖子,运行大约需要 5 分钟。

瓶颈是什么?我是否使用了错误的方法?

export const getAndStoreLatestKPI = async () => {
  console.log("start kpi");
  try {
    const marketCaps = await getKPI();
    const stocks = await mongoose.model("stock").find().exec();

    for (const stock of stocks) {
      const marketCap = marketCaps.find(
        (marketCap) => marketCap.i === stock.insId
      );

      if (marketCap != null) {
        const marketCapAdjustedVal =
          stock.country === "Finland" ? marketCap.n * 10 : marketCap.n;

        const update = {
          marketCap: marketCapAdjustedVal,
        };
        console.log(marketCapAdjustedVal);
        await mongoose
          .model("stock")
          .findOneAndUpdate({ insId: stock.insId }, { update });
      }
    }
    console.log("done");
    return Promise.resolve();
  } catch (err) {
    return Promise.reject(err);
  }
};

export const getKPI = async (kpiId: number) => {
  try {
    const kpiFetch = await Axios.get(someurl);
    return Promise.resolve(kpiFetch.data.values);
  } catch (err) {
    return Promise.reject(err);
  }
};

【问题讨论】:

  • 什么是marketCaps?是另一个系列吗?为什么不等待它返回的承诺呢?
  • 我从外部 api 获取它。我在等待它?
  • 否,或者是。这取决于 API 是否返回承诺。我猜它是否对您有用,那么您不必等待它
  • @TomSlabbaert 我添加了 getKPI 函数。它是在回报一个承诺吗?
  • 一个async函数默认总是返回一个promise。即使实际功能实际上并没有做任何异步操作。 (在这种情况下不正确,因为 Axios.get 是异步的)。

标签: mongodb mongoose


【解决方案1】:

所以主要的瓶颈是你的for 循环。对于每个库存商品,您需要执行几个“昂贵”的操作,例如从外部 API 获取数据 + 一次更新,并且您正在一个接一个地执行这些操作。

我建议你做的是一次循环几个项目。类似于multithreading 的想法。 在nodejs 中有几种不同的解决方案,例如nodejs worker threads

不过,我个人使用并推荐使用 bluebird,它为您提供了这种能力以及许多其他开箱即用的能力。

一些示例代码:

import Bluebird = require('bluebird');
const stocks = await mongoose.model("stock").find().exec();

await Bluebird.map(stocks, async (stock) => {
     const marketCap = marketCaps.find(
        (marketCap) => marketCap.i === stock.insId
      );

      if (marketCap != null) {
        const marketCapAdjustedVal =
          stock.country === "Finland" ? marketCap.n * 10 : marketCap.n;

        const update = {
          marketCap: marketCapAdjustedVal,
        };
        console.log(marketCapAdjustedVal);
        await mongoose
          .model("stock")
          .findOneAndUpdate({ insId: stock.insId }, { update });
      }
}, {concurrency: 25})
// concurrency details how many concurrent process run parallel. the heavier they are the less you want concurrent for obvious reasons.

【讨论】:

  • 外部 API 调用不在 for 循环中。 ES Promise.all 和 bluebird 不一样吗?
  • 可以使用原生的Promise.all,但无法控制concurrency的速率。在大多数情况下,这可能会导致您的流程中出现OOM 错误
猜你喜欢
  • 2018-04-05
  • 2016-01-11
  • 1970-01-01
  • 2017-01-18
  • 2015-10-04
  • 2014-06-14
  • 1970-01-01
  • 2020-08-02
相关资源
最近更新 更多