【问题标题】:Async await in nodejs for mongodb query not working [duplicate]nodejs中的异步等待mongodb查询不起作用[重复]
【发布时间】:2021-06-26 20:45:26
【问题描述】:

我有以下架构

const schema = new Schema(
  {
    ImageId: { type: String, ref: models.IMAGES },
    reportedBy:[
      userId:{type:String, ref: models.USER}
    ]
  }
);

class ImageReport {}

schema.loadClass(ImageReport);

module.exports = model(models.IMAGEREPORT, schema);

以下代码

reportImage: async (req, res, next) => {
    try {
      const { ImageId } = req.params;
      const image = await Image.findOne({ ImageId }); // there is an image schema with fields: ImageId and url
      if(!image) 
        return res.status(400).send({
           statusCode: 400,
           error:"CANNOT FIND THE IMAGE",
           data: {},
        });

      const userId = "some userId";
      try{
        let imageReports = await ImageReport.findOne({ ImageId:ImageId})
        if(imageReports){
          imageReports.reportedBy.forEach(rep=>{
            if(rep.userId===userId)
         // this error should be returned immediately. Instead it goes to ImageReport.updateOne() call
              return res.status(400).send({
                statusCode: 400,
                error: "YOU HAVE ALREADY REPORTED THIS IMAGE",
                data: {},
               });
          });
        }  
      } catch(err){
        return res.status(400).send({
             statusCode: 400,
             error: error,
             data: {},
            });;
      }
       
   // this is called even if the error is found in the above try catch block
      await ImageReport.updateOne(
        {ImageId:ImageId},
        {
          $push:{
            reportedBy:userId
          }
        },
        {upsert:true},
        function (error) {
          if (error) {
            return res.status(400).send({
             statusCode: 400,
             error: error,
             data: {},
            });
          }
        }
      )
      
      return res.status(200).send({
        statusCode: 200,
        error: 'THE IMAGE WAS REPORTED SUCCESSFULLY',
        data: {},
      });

    } catch (e) {
      return res.status(400).send({
        statusCode: 400,
        error: error,
        data: {},
      });
    }
  },

当我运行此查询并假设用户已经报告了图像(即,他们的 userId 在“reportedBy”数组中)时,API 调用不会尽快返回错误。相反,它转到 ImageReport.updateOne() 调用并插入文档,然后返回错误消息(“你已经报告了这个图像”)

谁能告诉我为什么 async await 不能正常工作?我也收到以下错误

Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on 
unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:16920) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

【问题讨论】:

  • 问题不在于async/await,而在于你不能从forEach“循环”中return

标签: node.js mongodb error-handling async-await promise


【解决方案1】:

我认为这是一个重构的案例。当然会返回错误 400,但它只会停止插入错误的范围。请注意,此错误在第二次捕获时发送,但第一个(更新)的范围仍然存在。

由于 JS 在作用域上可能很棘手,我会做一些改变来避免这种行为:

  1. 拆分函数 - 在调用的不同函数中插入和更新逻辑(使用等待)。例如:
findProcessedImageReport: async (params) => {
   // ...
   if(imageReports){
          imageReports.reportedBy.forEach(rep=>{
            if(rep.userId===userId)
                throw new Error("YOU HAVE ALREADY REPORTED THIS IMAGE");
          });
        }

// ... not error 
   return imageReportData;
}

updateReportImage: params => { // ... logic }

  1. 在调用此函数时处理一次错误。在函数本身,我会抛出错误而不是直接响应它来表达。所以,我会在快速响应的地方得到抛出的错误。
reportImage: async () => {
   try {
       const processedImageReport = await findProcessedImageReport(params)
       // The current flow would be stopped if got error "error: "YOU HAVE ALREADY REPORTED THIS IMAGE"

       await processUpdateImageReport(params)
       return res.status(200).json({success: true, ...data})
    } catch (err){
       return res.status(400).json(err)
    }
}

【讨论】:

  • 真的很棒......非常感谢......它工作得很好,没有任何错误或警告......太好了! :)
【解决方案2】:

使用for of 而不是forEach 方法,因为您的return 只是完成了forEach 内部某个迭代的回调:

for (const rep of imageReports.reportedBy) {
  if(rep.userId===userId)
  // this error should be returned immediately. Instead it goes to ImageReport.updateOne() call
  return res.status(400).send({
    statusCode: 400,
    error: "YOU HAVE ALREADY REPORTED THIS IMAGE",
    data: {},
  });
}

【讨论】:

    猜你喜欢
    • 2020-06-19
    • 2019-01-03
    • 1970-01-01
    • 2018-03-22
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    相关资源
    最近更新 更多