1

I have a case in which I am running a loop for n times, and for each loop call, I am to check the presence of a value in a couple of mongo collections say A, and B , and then upsert in a collection C

for (i=0;i<n;i++)
{
   Console.log("started call to doSomething for " + i);
   doSomething(i);
   Console.log("End call to doSomething for " + i);
} 

function doSomething(i)
{
  console.log("started doing something for " + i);
  calltoMongo(i);
}

function calltoMongo(i);
{
   common.db.collection.find(err,result)
  {
    console.log("here for " + i);
   common.db.collection.insert(<some object >);
  }
}

Above is just pseudo code of what I have, the output comes very crazy lets say i run it for 3 elements in my for loop

the output would be

started call to doSomething for 1
started doing something for 1
End call to doSomething for 1
started call to doSomething for 2
started doing something for 2
End call to doSomething for 2
here for 2
here for 2

I am at my wits end, I understand something funny happening due to scope resolution and that because only last element value remains when the loop ends, and the mongo side code starts working only after wards the value that remains in scope is the last value, But i don't know a way to fix it for real, even if I put sleep at end of call to Mongo function , it doesn't help.

Brij Raj Singh - MSFT
  • 4,903
  • 7
  • 36
  • 55

1 Answers1

0

You are creating a closure where each call to the function retains a reference to the stack frame containing i. Because the DB function is asynchronous it only runs once i has achieved its final value.

Related

In terms of actually resolving your problem I would use promise chaining unless you need them to run in parallel.

Community
  • 1
  • 1
Jared Smith
  • 19,721
  • 5
  • 45
  • 83
  • but the db function runs X times, as much as the for loop runs for , its only that it ends up running with the last / final value; should i try asynch – Brij Raj Singh - MSFT May 03 '15 at 12:33
  • I would indeed like them to run in parallel. – Brij Raj Singh - MSFT May 03 '15 at 12:34
  • Right. The calls are retaining a *reference* to the environment containing `i`. Your code/problem indicates that you are expecting `i` to be passed by *value* (not an unreasonable proposition). So it makes X function calls (where X is the number of times the loop runs) but the functions are getting the value of `i` at the time they run which is the final value of `i` – Jared Smith May 03 '15 at 12:35
  • Yes I'd use async if none of the subsequent updates depend on earlier ones. Just make sure you understand: when you have functions calling functions calling functions like that, each one of them has access to the call stack until (and in some cases after) they return. So each insert call has a reference to the (same) current state of `doSomething`, which as you can see from the order of your console logging has assumed its final value by the time they run. – Jared Smith May 03 '15 at 13:06