1

I'm relatively (read: very) new to MongoDB, and am encountering something that's got me confused.

I have an array of Employee objects, each of which looks basically like this:

{
  "Name" : "Jack Jackson",
  "Title" : "Senior Derp Engineer",
  "Specialties" : [
    "Kicking",
    "Screaming",
    "Throwing Tantrums"
  ]
}

...and I'd like to insert each of them into my collection as a document.

This is the code (simplified):

var collection = db.collection('Employees');
for (var ix=0; ix<allEntries.length; ix++) {
  var item = allEntries[ix];
  collection.insert(item, function(err, docs) {
    if (err) { MyErrorCallback(err); }
    else {
      // Insert specialties
      console.log(item["_id"] + ": " + item["Specialties"].length + " specialties.");
      // ...Code goes here which will insert a document into another collection associating the item's ObjectID with each specialty in the list.
    }
  });
}

I'd expect that for a list of 100 Employees, my console output would consist of the newly-created ObjectID for each of the 100 items in allEntries, along with a count of the number of specialties in that item. Instead, what I get is the ObjectID for the first item inserted, and the count of the Specialties for the first item inserted, repeated 100 times.

Why is this? How do I access the just-inserted item including its newly-generated ID, so I can do things with it? This seems like some kind of scoping issue, but it's not making sense to me.

Many thanks.

UPDATE: I self-answered below with the correct way to retrieve the object; however I'm still very interested if anyone can explain the variable scoping here. It's confusing.

3 Answers 3

4

This is the way Node.js works and I spent soooo much time to understand what's happening in such situation like yours. Node.js wants to be non-blocking, which means that this code is ran asynchronous.

As an example:

Your for loop runs and sets item to e.g. "1". Now it calls the mongoDB function. Everything is fine until now. The thing is: Node.js will not wait with continuing the for loop until your callback function is called. The for loop will go on. This means, that item will get the value e.g. "2" now. When the callback is called, the for-loop will have ended. Every single function will log: "2", because that's the actual value of the variable.

You can see an example if you print out the value of i inside the callback function.

Sign up to request clarification or add additional context in comments.

1 Comment

This explanation was very helpful. Thanks!
1

Your docs variable in the insert callback function contains the new inserted item with its objectID so just do what you want with it.

Try console.log(docs) inside the callback to see what is happening.

Comments

0

I figured out how to get the object:

var collection = db.collection('Employees');
for (var ix=0; ix<allEntries.length; ix++) {
  var item = allEntries[ix];
  collection.insert(item, function(err, docs) {
    if (err) { MyErrorCallback(err); }
    else {
      // Insert specialties
      var insertedItem = docs["ops"][0];
      console.log(insertedItem["_id"] + ": " + insertedItem["Specialties"].length + " specialties.");
      // ...Code goes here which will insert a document into another collection associating the item's ObjectID with each specialty in the list.
    }
  });
}

(Info about that "ops" item here).

However, I definitely don't understand the way scope is working here, since the function passed into collection.insert() has access to item, but it's not behaving in any way that makes sense to me...?

1 Comment

The callback function does not have access to item but it has the second param called "docs" that contains the result or results of the insert. That is the concept of callback, hey call me with the results when you end the I/O database work. and mongoose launches the callback when the insert stament finish successfully or with an error. You can name this param anything intead of "docs". For example result, results or item.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.