Reputation: 13
I'm very new to nodejs and javascript in general. I'm trying to implement a response from a controller method which will return a result from a query. Currently, the response is sent before the query is finished. Would really appreciate some advice on how to approach this.
I've tried implementing a callback, but cannot seem to get it to work as expected. Setting a breakpoint on project.push() I know it pushes, only after the response has been sent.
function getProjects(callback){
var projects = [];
Project.find({}, function (err, docs){
if (!err){
docs.forEach((doc) => {
Task.find({project_id: doc._id}, function(err, tasks){
var tasks_count = tasks.length;
var project = {
name: doc.name,
tasks: tasks_count,
_id: doc._id
};
projects.push(project);
});
});
} else {
throw err;
}
callback(projects);
});
};
router.get('/projectlist', function (req, res) {
getProjects(function(projects){
res.json(projects);
});
});
The code above will send an empty response and then go ahead and push the actual results to the array. Any help is greatly appreciated!
Upvotes: 1
Views: 2020
Reputation: 144
To ensure sequential execution you can use the "async + await" syntax.
https://javascript.info/async-await
Upvotes: 1
Reputation: 620
You're calling the callback in the wrong place. Notice that Task.find is asynchronous. You can use async https://www.npmjs.com/package/async to handle async calls.
function getProjects(callback) {
var projects = [];
Project.find({}, function (err, docs) { //first async call
if (!err) {
async.each(docs, (doc, key, callback) => {
Task.find({ project_id: doc._id }, function (err, tasks) { //second async call
var tasks_count = tasks.length;
var project = {
name: doc.name,
tasks: tasks_count,
_id: doc._id
};
projects.push(project);
return callback(); //this callback tell async that it can move to the next element in the array
});
}, function (err) { //this function will be call after all the element in the array are returned
if (err) {
return callback(err);
}
// now you can call your callback, the convention is to call the callback with callback(error, data);
callback(null, projects); //we have no errors so we pass null
});
} else {
return callback(err);
}
});
};
I didn't run the code, but it should work. hoping the comments will help you.
Upvotes: 2