nodejs 中的异步等待 mongodb 查询不起作用

Async await in nodejs for mongodb query not working

我有以下架构

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: {},
      });
    }
  },

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

谁能告诉我为什么 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.

使用 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: {},
  });
}

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

由于 JS 的范围很棘手,我会做一些更改来尝试避免这种行为:

  1. 拆分函数 - 在调用的不同函数中插入和更新逻辑(使用 await)。例如:
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)
    }
}