正确使用MongoDB node.js`insertMany`的方式,以便不会阻塞

时间:2019-07-05 14:26:56

标签: node.js mongodb async-await

在node.js应用程序中,我想使用insertMany插入很多文档(实际上,大约是1万个)。我遇到以下问题:insertMany(用await调用)正在运行时,直到insertMany调用完成之后,node.js进程才从处理循环中进行任何处理。

这是预期的行为吗?我将如何“正确地进行”操作,以便我的服务在此期间仍能处理请求?我本来希望await insertMany自动启用此功能,因为它是异步的,但似乎并非如此。

代码段:

exports.writeOrg = async (req, res, next) => {
  logger.debug('orgs.writeOrg()');
  // ...
  try {
    // ...
    logger.debug('Starting processing of data.');
    const newOrgDocs = await processLdapUsers(tenantId, ldapUsers);
    logger.debug('Processing of data finished.');

    const orgModel = getOrgModel(tenantId);
    // Now delete the entire collection
    logger.debug(`Delete entire org collection in tenant ${tenantId}`);
    await orgModel.deleteMany({});
    // And add the new org information; this replaces what was there before
    logger.debug(`Inserting org structure to tenant ${tenantId}`);
    // This is the call which seems to block: --->
    await orgModel.insertMany(newOrgDocs);
    // <---
    logger.debug(`Finished inserting org structure to tenant ${tenantId}`);
    // ...
  } catch (err) {
    // ...
    // error handling
  }
}

writeOrg函数是一个常规的快速请求处理程序;有效负载是一个通常具有1000-20000条记录的JSON数组;在测试案例中,我有6000条记录,JSON总大小约为6 MB。本地写大约需要1.5秒,写到MongoDB Atlas(最便宜的测试层)大约需要20秒,这就是发生此问题的时间。

解决方法:如果我将数据分成较小的块,例如一次50条记录,事件循环会不时处理一些其他请求的数据。但是,尽管insertMany函数是一个async函数调用,所以我并不希望这样做。

1 个答案:

答案 0 :(得分:0)

有很多问题使速度变慢,而最重要的实际上是问题中未提到的问题:我正在使用 Mongoose 作为Mongo DB的“ ORM”包装。我不知道这会对运行时产生如此大的影响。

在使用Chrome node.js调试工具检查了实际运行时之后,这里发生的事情是 Mongoose包装并验证数组中的每个文档,这会花费大量时间。

>

BSON转换也需要时间,但是文档包装是最耗时的事情。

这意味着:猫鼬不是超级适合快速插入(或阅读,FWIW);如果您需要速度,则直接使用本机Mongo DB驱动程序是可行的方法。如果您对纯速度的需求不是很大,并且想要Mongoose的便利,则Mongoose可以通过执行验证和添加默认值等来增加价值。