nodejs和mongodb(mongojs):尝试在for循环中查询和更新数据库

时间:2013-01-22 18:14:44

标签: javascript node.js mongodb mongojs

我正在编写一个多人游戏(mongojs,nodejs),并试图找出如何根据游戏结果更新用户统计数据。我已经编写了代码来计算所有后期游戏统计数据。当我尝试在for循环中更新用户的统计信息时出现问题。这就是我得到的:

//Game Stats
var tempgame = {
    gameid: 1234,
    stats: [
        {
            score: 25,
            user: 'user1'
        },
        {
            score: 25,
            user: 'user2'
        }
    ]
}


for(i = 0; i < tempgame.stats.length; i++){
    db.users.find({ username: tempgame.stats[i].user }, function(err, res){
        if( err != null){
            //handle errors here.
        } else {
            var userstats = res[0].stats;
            if( tempgame.stats[i].score > userstats.bestscore ){ //this is where it chokes 
                userstats.bestscore = tempgame.stats[i].score;
            }

            //code here to pass back new manipulated stats
        }
    });
}

一切正常,直到我尝试在回调函数中使用tempgame对象。它说“无法读取未定义的属性'得分'”。这只是一个范围问题吗?

此外,我认为这可能是回调函数本身的问题。也许循环会在回调运行之前递增。但即使在这种情况下,分数应该在那里,它只是从错误的数组索引中拉出来......这就是让我相信它可能只是一个范围问题。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:7)

你被臭名昭着的“defining functions inside a loop”问题绊倒了。

改为使用“forEach”:

tempgame.stats.forEach(function (stat) {
    db.users.find({ username: stat.user }, function(err, res){
        if( err != null){
            //handle errors here.
        } else {
            var userstats = res[0].stats;
            if( stat.score > userstats.bestscore ){ //this is where it chokes 
                userstats.bestscore = stat.score;
            }

            //code here to pass back new manipulated stats
        }
    });
});

答案 1 :(得分:2)

你问题的一部分就像他在回答你的问题时说的那样,并且正如你所怀疑的那样。在调用回调之前,i变量正在发生变化。

问题的另一半是因为您的数据库调用尚未返回。由于NodeJS的异步特性,您的循环将在数据库调用完成之前完成。此外,您的数据库调用不一定按照您调用它们的顺序返回。你需要的是某种流量控制,如async.js。使用async.map将允许您并行地对数据库进行所有调用,并在完成所有数据库调用后将它们作为可以使用的值数组返回。

async.map(tempgame.stats, function(stat, callback){
  db.users.find({ username: stat.user }, function(err, res){
      if( err != null){
          callback(err);
      } else {
          callback(null, res[0].stats);
      }
  });      
}, function(err, stats){
  if(err){
    //handle errors
  } else{
    stats.forEach(function(stat){
      //do something with your array of stats
      //this wont be called until all database calls have been completed
    });
  }
});

答案 2 :(得分:0)

除了上述内容,如果要将结果返回给应用程序, http://nodeblog.tumblr.com/post/60922749945/nodejs-async-db-query-inside-for-loop