【问题标题】:How to use async parallel for multiple Queries如何对多个查询使用异步并行
【发布时间】:2018-02-12 05:45:43
【问题描述】:

我是 javascript 新手。

我尝试使用 async.parellel 函数。 并获取“reviewArr”并返回它。

请看我的代码。

app.get('/api/wherecritique/reviews/search/:author', function(req,res){
   var reviewArr = [];
   Critique.find({author:req.params.autho}, function(err,cris){
       var i =0;
       var f = function(reviewID)
      {
          Review.findOne({id:reviewID}, function(err, review)
          {
               reviewArr.push(review);
          }
      }
      var tasks = {};
      for(var j =0; j<cris.length; j++)
      {
          tasks['func'+j] = f(cris[j].reviewID);
      }
      async.parallel(tasks, function(err, results){
          console.log(results);
          res.json(reviewArr);
      });
  });
});

我使用了 mongoose+express+node.js。 Critique, Review 是模型(猫鼬模式)。

当我运行此代码时,我会收到此消息。 “任务不是函数”

请帮助我如何解决此错误? 问候。

【问题讨论】:

    标签: javascript node.js mongodb express mongoose


    【解决方案1】:

    您没有正确设置函数。预期的参数是带有 callback 参数的 function() 包装器,该参数在包含的异步函数完成时传递给。

    您实际上也只是想要async.map 而不是您正在做的事情,因为它的输出是循环调用的结果数组。因此无需将结果推送到外部变量中:

    app.get('/api/wherecritique/reviews/search/:author', function(req,res) {
    
      Critique.find({author: req.params.author}, function(err,cris) {
    
        async.map(
          cris.map( c => c.reviewID ),
          function(id, callback) {
            Review.findOne({ id: id }, callback);
          },
          function(err,results) {
            if (err) throw err; // or something with err
            console.log(results);
            res.json(results);
          }
        );
    
      });
    });
    

    但老实说,你真的应该在这里使用 Promises,而不是导入外部库

    app.get('/api/wherecritique/reviews/search/:author', function(req,res) {
    
      Critique.find({author: req.params.author}, function(err,cris) {
    
        Promise.all(
          cris.map( c => Review.findOne({ id: c.reviewID }) )
        ).then( results => {
          console.log(results);
          res.json(results);
        }).catch( e => console.error(e) );
    
      });
    
    });
    

    或者以更现代的方式使用async/await

    app.get('/api/wherecritique/reviews/search/:author', async (req,res) => {
    
      try {       
        let cris = await Critique.find({author: req.params.author});
    
        let results = Promise.all(
          cris.map( c => Review.findOne({ id: c.reviewID }) )
        );
        console.log(results);
        res.json(results);
      } catch(e) {
        console.error(e);
      }
    
    });
    

    但实际上,这与 JavaScript 完全无关,您确实应该使用 MongoDB 功能。

    在支持的情况下使用$lookup

    app.get('/api/wherecritique/reviews/search/:author', async (req,res) => {
    
      try {       
        let results = await Critique.aggregate([
          { $match: { author: req.params.author } },
          { $lookup: {
            from: Review.collection.name,
            localField: 'reviewID',
            foreignField: 'id'
            as: 'reviews'
          }},
          { $unwind: '$reviews' }
        ]);
    
        results = results.map( r => r.reviews );
        console.log(results);
        res.json(results);
    
      } catch(e) {
        console.error(e);
      }
    
    });
    

    或者,如果您没有,那么只需将所有 id 值传递给 $in

    app.get('/api/wherecritique/reviews/search/:author', async (req,res) => {
    
      try {       
        let cris = await Critique.find({ author: req.params.author });
    
        let results = await Review.find({ id: { $in: cris.map( c => c.reviewID ) } });
        console.log(results);
        res.json(results);
    
      } catch(e) {
        console.error(e);
      }
    
    });
    

    这意味着对数据库的“一次”或“两次”实际调用取决于您的 MongoDB 版本。根本不需要循环异步调用。


    最后,正如上面所有解释的那样,它真的没有必要,但async.parallel的正确用法是:

    app.get('/api/wherecritique/reviews/search/:author', (req,res) => {
    
      Critique.find({author: req.params.author}, (err,cris) => {
    
        var tasks = cris.map( c => (callback) =>
            Review.findOne({ id: c.reviewID }, callback);
        );
    
        async.parallel(
          tasks,
          (err,results) => {
            if (err) throw err; // or something
            console.log(results);
            res.json(results);
          }
        )
      });
    });
    

    【讨论】:

    • 我见过的最佳答案。还有关于异步的好讲座。非常感谢。
    • @fastworker399 你可以考虑Accepting the answer,因为这通常向人们表明它确实是问题的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    相关资源
    最近更新 更多