javascript - Nodejs 和 Mongoose : Await stops loop

标签 javascript node.js mongodb mongoose async-await

我正在解析 CSV 并处理每条记录,以使用 Mongoose 将其插入到我的 MongoDB 中。我已经正确地从 CSV 中获取了一个数组,但是当我开始使用 forEach (和 async/await)对其进行迭代时,它就停在那里了。

这是我的代码:

const csv = require('csv-parser');
const fs = require('fs');
const Customer = require('../../app/models/Customers');

const projects = [];

const processRecords = async () => {
  try {
    const usableProjects = projects.filter((project) => project['cust_number customer']);
    const customerNames = [...new Set(usableProjects.map((item) => item['Parent Name']))];
    await customerNames.forEach(async (customerName) => {
      console.log('Point 1');
      const existingCustomer = await Customer.find({Name: customerName});
      console.log('Point 2'); //<======= THIS CODE IS NEVER REACHED
      if (existingCustomer.length > 0) {
        console.log(`${customerName} already exists. Skipping...`);
        return;
      }
      const customerRecord = usableProjects.find((project) => project['Parent Name'] === customerName);
      const newCustomer = {
        Name: customerName,
        Source: 'CSV',
        Initials: customerRecord.Initials,
        Code: customerRecord.Codename,
      };
      const newCustomerRecord = await Customer.create(newCustomer);
      if (newCustomerRecord) {
        console.log(`Customer ${newCustomerRecord._id} created`);
      }
    });
  } catch (err) {
    console.log(err);
  }
};

fs.createReadStream('customer_table.csv')
  .pipe(csv())
  .on('data', async (data) => projects.push(data))
  .on('end', async () => {
    processRecords();
  });

这是输出:

Point 1
Point 1
Point 1
Point 1
Point 1
Point 1
Point 1
Point 1
Point 1
Point 1
Point 1
Point 1
Point 1

我知道这可能与我未处理更正的同步/异步代码有关。但我一直无法修复它。提前致谢。

最佳答案

首先,让我们将 try-catch 放在 Customer.find() 上 (为了清楚起见,我将简化您的代码。并且我会将 Customer.find() 替换为 f())

async function success() { return "Hurrah!" }
async function failure() { throw new Error("Oops!") }

const customerNames = [1, 2, 3]

const processRecords1 = async (f) => {
    try {
        await customerNames.forEach(async (customerName) => {
            try {
                console.log('Point 1');
                const existingCustomer = await f()
                console.log('Point 2', existingCustomer);
                // ...
            } catch (err) {
                console.log('Point 3', err);
            }
        });
    } catch (err) {
        console.log('Point 4', err);
    }
};
setTimeout(() => processRecords1(success), 0);

输出:

Point 1
Point 1
Point 1
Point 2 Hurrah!
Point 2 Hurrah!
Point 2 Hurrah!

如您所见,如果f = success 则达到“Point 2”。所以这是第一个问题:您的 Customer.find() 失败并且您没有看到异常。 让我们尝试从 f() 抛出异常,只是为了证明这一点......

setTimeout(() => processRecords1(failure), 100);

输出:

Point 1
Point 1
Point 1
Point 3 Error: Oops!
Point 3 Error: Oops!
Point 3 Error: Oops!

是的,如果f()失败,我们永远不会到达“第2点”。但现在我们确实在“第 3 点”中看到了一个错误。所以我们可以到此为止。

但是让我们尝试在 processRecords() 的顶层捕获异常并到达“第 4 点”。 正如已经提到的,forEach() 不返回值。让我们尝试一下map()

const processRecords2 = async (f) => {
    try {
        await customerNames.map(async (customerName) => {
            console.log('Point 1');
            const existingCustomer = await f()
            console.log('Point 2', existingCustomer);
            // ...
        });
    } catch (err) {
        console.log("Point 4", err);
    }
};
setTimeout(() => processRecords2(failure), 200);

输出:

Point 1
Point 1
Point 1
Uncaught (in promise) Error: Oops!
Uncaught (in promise) Error: Oops!
Uncaught (in promise) Error: Oops!

运气不好。这是因为 map() 确实返回一个值,但它是一个 Array,而不是 Promise。您不能 await 获取 Promise-s 数组,但可以使用 Promise.all() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

const processRecords3 = async (f) => {
    try {
        await Promise.all(customerNames.map(async (customerName) => {
            console.log('Point 1');
            const existingCustomer = await f()
            console.log('Point 2', existingCustomer);
            // ...
        }));
    } catch (err) {
        console.log("Point 4", err);
    }
};
setTimeout(() => processRecords3(failure), 300);

输出:

Point 1
Point 1
Point 1
Point 4 Error: Oops!
Point 4 Error: Oops!
Point 4 Error: Oops!

那个。将 await customerNames.forEach(...) 替换为 await Promise.all(customerNames.map(...) 就可以了。

关于javascript - Nodejs 和 Mongoose : Await stops loop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59507374/

相关文章:

javascript - 无需模板即可访问 Meteor 中的 mongodb 集合

javascript - 在 head 标签中动态添加一个 <link rel ="canonical"

javascript - 变量在通过 fetch 分配之前使用

node.js - node-fetch:为什么推荐使用 `signal` 而不是 `timeout` ?

javascript - Jake 任务在异步任务完成之前完成

ruby-on-rails - Mongo::Error::UnsupportedFeatures(位于 (localhost:27017) 的服务器报告有线版本 (2),但此版本的 Ruby 驱动程序至少需要 (6)。)

javascript - AngularJS中的严格模式过滤器

javascript - 如何让 ZMQ 路由器在繁忙时引发错误?

node.js - WebSocket 服务器不适用于 SSL

javascript - Mongoose 中嵌入文档的重复键错误索引