【问题标题】:Mongoose Async Call Issue with Find Query查找查询的 Mongoose 异步调用问题
【发布时间】:2015-07-08 18:14:37
【问题描述】:

我有 var movieRecommendation,它是根据来自 Mongo DB 的数据填充的。问题是 Mongoose Movie.findOne() 调用是 asycn 调用,它不允许我获得最终填充的 movieRecommendation,我需要将其作为响应发回。

exports.getRecommendation=function(req,res){
var movieRecommendation = [];
var id=req.params.id;
console.log('----- Get User Recommendation - ' +  id);
var url = 'http://52.8.48.113:8080/recommender-server/recommender/v1/recommendations/'+id+'.do';
//make http get request
request({
    url: url,
    json: true
}, function (error, response, recommendations) {
       // res.json(recommendations);

    if (!error && response.statusCode === 200) {
        recommendations.forEach(function(entry) {

             **Movie.findOne({'id':parseInt(entry.itemId)},function(err, movieData){**
                entry.movie = movieData;
                movieRecommendation.push(entry);
               //console.log('rec', movieRecommendation);
                 console.log(movieRecommendation.length);
            });


        });

    }
    console.log("====Final========"+movieRecommendation.length);
    //Output = 0

});

    res.json(movieRecommendation); // Here movieRecommendation is coming as black Array

};

请告诉我如何才能最终填充 movieRecommendation var 以使其可用于响应。

【问题讨论】:

标签: node.js mongodb mongoose


【解决方案1】:

对于此类问题,我们可以使用Async 库。要在所有操作完成后最终填充数据,我们可以使用 Async Library 中的 async.each 集合。

例如: 注意:通过此命令安装 Async npm install async 使用异步库

    var async = require("async");

    var recomenmendations = [{"data2" : "value2"} , {"data1" : "value2"}, {"data3" : "value3"}, {"data4" : "value4"} ]  

    var movieRecommendation = [];

    async.each(recomenmendations,

      function(recomenmendationItem, callback){


            console.log("Here you can query the required data using current recomenmendations ITEM");
            console.log(recomenmendationItem);
            callback();

             // Movie.find({'id':parseInt(recomenmendationItem.itemId)},function(err, movieData){

          //           recomenmendationItem.movie = movieData;
          //           movieRecommendation.push(entry);
          //        callback();        
          //    });



      },

      function(err){

        console.log("here you can send your resopnse");
        console.log("This section will be executed once all the recomenmendations are processed");
        //res.json(movieRecommendation)

      }
    );

您可以查询 mongoDB,如注释部分所示。您应该在为迭代执行所有操作后使用 callback()

【讨论】:

  • 嗨,Prabhu,给定的代码按预期工作正常,但是当我再次在 callback() 之前进行 Mongo 调用时,我遇到了与以前相同的问题。
【解决方案2】:

正如我在我的一个 cmets 中提到的,使用传递给迭代器函数的 callback 并在 Movie.findOne() 回调中调用它。这样,async.each 就会知道每个步骤何时完成:

async.each(recomendations, function (recomendationItem, callback) {

    Movie.findOne({'id':parseInt(entry.itemId)},function(err, movieData){

        if (err) return callback(err); // if you have an error on you search, just pass it to the iterator callback

        recommendationItem.movie = movieData;
        movieRecommendation.push(recommendationItem);

        callback();
    });

}, function (error) {

    if (error) return res.json ({ error: error }); // you should also check if an error ocurred

    res.json(movieRecomendation);

});

只是要指出:你也可以使用async.eachSeries,它只会在前一个返回时调用你的迭代的下一步(如果这对你很重要,但我认为这不是你的情况)并且它具有相同的签名。

【讨论】:

    【解决方案3】:

    @Vivek Panday 替换您的 exports.getRecommendation 函数中的以下代码以获得您的预期输出。如果我们使用 callback 函数,我们不需要使用 count 变量。重要的是我们必须在所有过程完成后使用 callback();。我认为您在您制定的示例中没有正确使用回调函数。使用以下代码如果有任何问题请告诉我。

         var async = require('async');
         var request = require("request");
    
          var movieRecommendation = [];
          var id=req.params.id;
          console.log('----- Get User Recommendation - ' +  id);
          var url = 'http://52.8.48.113:8080/recommender-server/recommender/v1/recommendations/'+id+'.do';
    
          //make http get request
          request({
              url: url,
              json: true
          }, function (error, response, recommendations) {
    
              if (!error && response.statusCode === 200) {
    
                  console.log('recommendation lenght '+ recommendations.length);
    
                  async.each(recommendations,
    
                    function(recommendationItem, callback){            
    
                      Movie.findOne({'id':parseInt(recommendationItem.itemId)},function(err, movieData){
    
                          recommendationItem.movie = movieData;
                          movieRecommendation.push(recommendationItem);
                          //you have to use callback(); once all your process is done
                          callback();
    
                      });
    
                    },
    
                    function(err){
                      //you should use this function, this will be execute once all the process done
                      console.log(movieRecommendation);
                      console.log("finally callback");
                      res.json(movieRecommendation);
    
                    }
    
                    );
    
              }
    
    
        });
    

    【讨论】:

      【解决方案4】:

      我已经按照上面给出的建议进行了尝试.. var async = require("async");

      var recomenmendations = [{"data2" : "value2"} , {"data1" : "value2"}, {"data3" : "value3"}, {"data4" : "value4"} ]  
      
      var movieRecommendation = [];
      
      async.each(recomenmendations,
      
        function(recomenmendationItem, callback){
      
      
              console.log("Here you can query the required data using current recomenmendations ITEM");
              console.log(recomenmendationItem);
      
      
               // Movie.find({'id':parseInt(recomenmendationItem.itemId)},function(err, movieData){
      
                     recomenmendationItem.movie = movieData;
                      movieRecommendation.push(entry);
                       console.log("any data"); // line y     
                });
      
      callback();
      
        },
      
        function(err){
      
          console.log("here you can send your resopnse"); // line x
          console.log("This section will be executed once all the       
          recomenmendations are processed");
          //res.json(movieRecommendation)
      
        }
      );
      

      但仍然面临同样的问题 line x is printing before line y ,这又是同样的问题。

      但是我尝试了下面给出的一些方法并达到了预期的结果。

      exports.getRecommendation=function(req,res){
      var movieRecommendation = [];
      var id=req.params.id;
      console.log('----- Get User Recommendation - ' +  id);
      var url = 'http://52.8.48.113:8080/recommender-server/recommender/v1/recommendations/'+id+'.do';
      //make http get request
      request({
          url: url,
          json: true
      }, function (error, response, recommendations) {
             // res.json(recommendations);
      
          if (!error && response.statusCode === 200) {
      
          console.log('recommendation lenght '+ recommendations.length);
      
             // recommendations.forEach(function(entry) {
              var count=0;
              async.each(recommendations,function(recommendationItem){
                 //  console.log(recommendationItem);
                  Movie.findOne({'id':parseInt(recommendationItem.itemId)},function(err, movieData){
                      recommendationItem.movie = movieData;
                      movieRecommendation.push(recommendationItem);
                      count ++;
                      console.log('final res length : ' +  movieRecommendation.length);
                    console.log('final res length count : ' +  count +'  and item recomm lenght ' +  recommendations.length );
      
                  if(count === recommendations.length){
                      console.log(' =====Final=====> here you can send your response =========' +   movieRecommendation.length);
      
                      res.json(movieRecommendation);
                  }
      
                  });
      
                 // callback();
      
              });
      
      
          }
      
      
      });
      

      };

      我仍然愿意接受任何反馈和建议。

      【讨论】:

      • 您应该使用传递给迭代器函数的callback 并在Movie.findOne() 回调中调用它。这样,async.each 将知道每个步骤何时完成。所以,你不需要你使用的所有逻辑。
      • 我刚刚写了一个答案。请看看它是否适合你。
      猜你喜欢
      • 2017-09-05
      • 2016-08-12
      • 2018-01-17
      • 2015-04-09
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多