I had an array of ids and wanted to get the various items from the database that were associated with those ids. (Yes, yes, I know about the $in command. I don't know what I was thinking either.)
for(var id in ids) {This code set the land speed record for fastest turnaround from written code to "What on earth were you thinking, past Randall?" (2 days). While most of you probably have figured out what's wrong, let's look into the details. In a purely synchronous language, this makes sense. Loop through the array, find the entry associated with the id at that point in the array and add it to a return object. When we've reached the last point in the array, render our page with the generated object and close our database connection.
//Convert text id to BSON id
var BSON = mongo.BSONPure;
var b_id = BSON.ObjectID(ids[id]);
collection.findOne({_id: b_id}, function(err, document) {
if(err) { console.error(err); db.close(); return;}
returnObject[id] = document;
if(id == ids.length - 1) {
res.render('checkout', {classes: returnObject});
db.close();
}
});
}
Here's what really happens:
for loop executes, adding collection.findOne callbacks to the node callback "todo" pile. After the loop finishes, `id` is the last `id` in the array.
Sometime after the for loop finishes, the callbacks are executed, all with the last id. Since the last id will trigger the render and database close, only one callback is run. The rest encounter a closed database.
Fortunately, this had an incredibly simple answer: Use mongodb's $in function. I still had to loop through and convert to BSON ObjectIDs. This resulted in much simpler code that used callbacks the right way.
for(var i=0;i<ids.length;i++) {Now, there's only one callback, and it'll contain exactly the data we want it to. Any number of ids can and will be handled correctly.
var b_id = BSON.ObjectID(ids[i]);
b_ids.push(b_id);
}
collection.find({_id: {$in: b_ids}}).toArray(function(err, results) {
if(err) { console.error(err); db.close(); return;}
res.render('checkout', {classes: results});
db.close();
});
A whole blog post, because I forgot one ruttin' command...
No comments:
Post a Comment