0

I am working with NodeJS and MongoDB and on start I create collections and fill them in if they don't already exist. Right now this is just development , but with backups and things I could end up doing the same thing or something similar in production.

My question is what will happen to the iteration variable(i)? Will the callback use the correct value for that iteration? Or will it get some other value further down the list, or perhaps none at all?

ldb.createCollection('people', { strict: true }, function(err, col){
    if(err) { console.log('createCollection( people ) ', err); } 
    else { 
        for(var i in people){
            col.insert(people[i], { w: 1 }, function(err, doc){
                people[i]._id = doc._id;
            }
        }
    }
});

Edit: This is an object, not an array.

Arlen Beiler
  • 15,336
  • 34
  • 92
  • 135
  • Since `insert` seems to be asynchronous, then yes `i` will change before the callback is executed. See [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Bergi May 01 '14 at 23:26

1 Answers1

1

When the callback passed into insert is called, the value of i will not be preserved (it will most likely be the last key in people). If you want to preserve i, you could give it its own functional scope like this:

people.forEach(function(person, i) {
    col.insert(person, { w: 1 }, function(err, doc) {
        person._id = doc._id;
    });
});

edit: Using an anonymous function instead of the forEach method:

for(var i in people) {
    function(i) {
        col.insert(people[i], { w: 1 }, function(err, doc){
            people[i]._id = doc._id;
        });
    }(i);
}
SimpleJ
  • 13,812
  • 13
  • 53
  • 93
  • What about `(function(var1, var2){ /* do something */ }(this.var1, this.var2);`? Seems like I've seen that used in cases? How would that be done? Would it work? This is an object, not an array, so it doesn't have a foreach function. – Arlen Beiler May 01 '14 at 22:47
  • Yes. That would probably be a more precise solution to your problem. I will add an example of that to my answer. – SimpleJ May 01 '14 at 22:48
  • The only reason I would suggest using a `forEach` call is it's cleaner and avoids common issues associated with `for..in` loops (such as requiring the use of the `hasOwnProperty` method). – SimpleJ May 01 '14 at 22:52
  • my $0.02: i find it easer to scan when you use a different variable name inside the wrapper than out of it. repeating "i" works and preserves the orig, but it can be confusing... – dandavis May 01 '14 at 23:15