0

i'm trying to add a array of ranks into my Ladder Model and then after create a Game Object with the created ObjectIds from the Ladder model however the rankIds aray keep returning [] even though if i inside ladder.save log rank.id and it return the objectId

Code

router.post('/:name/:ranks', function(req, res, next) {

  var rankIds = [];
  var params = req.params;
  var ranks = params.ranks.split(',');


  for (var i in ranks) {
    var ladder = new Ladder({
      name: ranks[i]

    });

    ladder.save(function(err, rank) {
      rankIds.push(rank.id);
    });
  }

  console.log(rankIds);

  var game = new Game({
    name: params.name,
    ranks: rankIds

  });

  game.save(function(err) {
    if (err) {
      res.send(err);
    } else {
      res.json({ message: 'Game created!' });
    }
  });


});
Peter Pik
  • 11,023
  • 19
  • 84
  • 142
  • Possible duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Felix Kling Nov 07 '16 at 02:49

2 Answers2

0

You are doing the for..in loop and calling db save asynchronous function. But executing the console.log and game.save before the asynchronous operation completes. You should handle it.

Also, its better to use for loop (or) foreach for array instead of for..in.

I have modified the code to make sure console.log and game.save will be executed after all the asynchronous operations completed. I have used a vannilaJS here instead of other asynchronous & promise modules such as async, bluebird etc which you should consider.

But still worth looking at the below vannilaJS code which should be functional.

router.post('/:name/:ranks', function(req, res, next) {

  var rankIds = [];
  var errors = [];
  var params = req.params;
  var ranks = params.ranks.split(',');


  for (var i = 0; i < ranks.length; i++) {
    var ladder = new Ladder({
      name: ranks[i]    
    });

    ladder.save(function(err, rank) {
      if(err) {
         errors.push(err);
      } else {
         rankIds.push(rank.id); // Check: if it's a mongodb update then it could be '_id' instead of 'id'
      }

      saveGame();
    });
  }

  var saveGame = function() {
     if(rankIds.length + errors.length === ranks.length) {
        console.log(rankIds);

        var game = new Game({
           name: params.name,
           ranks: rankIds    
        });

        game.save(function(err) {
          if (err) {
            res.send(err);
          } else {
            res.json({ message: 'Game created!' });
          }
        });
     }    
  };
});
Aruna
  • 11,959
  • 3
  • 28
  • 42
0

Consider this:

var arr = [];

var save = (callback) => {
  var id = "id";
  setTimeout(function () {
    callback(null, id);
  }, 2000);
}

for (var i = 0; i < 5; i++) {
  save(function (err, id) {
    arr.push(id);
  });
}

console.log(arr); // Print: []

setTimeout(function () {
  console.log(arr); // Print: [ 'id', 'id', 'id', 'id', 'id' ]
}, 10000);

The save()function take some seconds to finish, so the first console.log(arr) would run before the for loop finish (or before any of save() function has finished). So, the arr is still empty.

But in the second console.log, ran after that 10 seconds, it will print out the value of arr with 5 values pushed in.

This is simply asynchronous in node js.

notme
  • 424
  • 5
  • 14