.map 函数中的异步验证

Asynchronous verification within the .map function

我正在使用 Node JS、Sequelize 和 Postgres 数据库开发应用程序的后端。

注册课程时,用户必须告知将链接到哪些组织、公司和教师。

组织 ID 通过数组传递到后端,我正在尝试进行检查以确保传递的 ID 存在。

到目前为止我所做的是:

const { organizations } = req.body;
const organizationsArray = organizations.map(async (organization) => {
  const organizationExists = await Organization.findByPk(organization);
  if (!organizationExists) {
    return res
      .status(400)
      .json({ error: `Organization ${organization} does not exists!` });
  }
  return {
    course_id: id,
    organization_id: organization,
  };
});
await CoursesOrganizations.bulkCreate(organizationsArray);

这个link有完整的controller代码,相信会方便理解。

当 !OrganizationExists 为真时,我得到 return 组织不存在。问题是当组织存在时,我得到以下 message error.

Array.map() 是 return 一个承诺数组,您可以使用 Promise.all() 解析为一个数组。在地图内部,你应该使用 throw new Error() 来打破地图 - 这个错误将由 Promise.all() 引发,然后你可以捕获它并 return 向客户端发送错误(或吞下它等)。

这是您的模式的更正版本,解决了 Promise 结果。

const { organizations } = req.body;
try {
  // use Promise.all to resolve the promises returned by the async callback function
  const organizationsArray = await Promise.all(
    // this will return an array of promises
    organizations.map(async (organization) => {
      const organizationExists = await Organization.findByPk(organization, { 
        attributes: ['id'], // we only need the ID
        raw: true, // don't need Instances
      });
      if (!organizationExists) {
        // don't send response inside the map, throw an Error to break out
        throw new Error(`Organization ${organization} does not exists!`);
      }
      // it does exist so return/resolve the value for the promise
      return {
        course_id: id,
        organization_id: organization,
      };
    })
  );

  // if we get here there were no errors, create the records
  await CoursesOrganizations.bulkCreate(organizationsArray);

  // return a success to the client
  return res.json({ success: true });
} catch (err) {
  // there was an error, return it to the client
  return res.status(400).json({ error: err.message }); 
}

这是一个重构版本,通过在一个查询中获取所有 Organizations,然后执行 checks/creating 和 Course 插入,速度会更快一些。

const { Op } = Sequelize;
const { organizations } = req.body;
try {
  // get all Organization matches for the IDs
  const organizationsArray = await Organization.findAll({
    attributes: ['id'], // we only need the ID
    where: {
      id: {
        [Op.in]: organizations, // WHERE id IN (organizations) 
      }
    },
    raw: true, // no need to create Instances
  });

  // create an array of the IDs we found
  const foundIds = organizationsArray.map((org) => org.id);

  // check to see if any of the IDs are missing from the results
  if (foundIds.length !== organizations.length) {
    // Use Array.reduce() to figure out which IDs are missing from the results
    const missingIds = organizations.reduce((missingIds, orgId) => {
      if (!foundIds.includes(orgId)){
        missingIds.push(orgId);
      }
      return missingIds;
    }, []); // initialized to empty array

    throw new Error(`Unable to find Organization for: ${missingIds.join(', ')}`);
  }

  // now create an array of courses to create using the foundIds
  const courses = foundIds.map((orgId) => {
    return {
      course_id: id,
      organization_id: orgId,
    }; 
  });

  // if we get here there were no errors, create the records
  await CoursesOrganizations.bulkCreate(courses);

  // return a success to the client
  return res.json({ success: true });
} catch (err) {
  // there was an error, return it to the client
  return res.status(400).json({ error: err.message }); 
}

如果你有一个 ID 数组并且你想检查它们是否存在,你应该使用 (in) 运算符,这使得你只访问数据库一次并一次获取所有记录(而不是在一个循环中一个一个地得到它们),在你得到这些记录之后你可以检查它们的长度来确定它们是否都存在。

const { Op } = require("sequelize");
let foundOrgs = await Organization.findAll({
  where: {
    id: {
      [Op.in]: organizationsArray,
    }
  }
});