Poot87 Poot87 - 5 months ago 261
Node.js Question

Node async callback was already called when trying to make a nested query

I am getting a Callback was already called error while trying to make asynchronous queries using the MEAN stack. I need the second callback to only trigger after the nested query has been completed (as per the comments in the code). Why am I getting this error?

Example of the route:

router.route('/teams/:user_id').get(function (req, res) {

TeamProfile.find({
Members : {
$in : [req.params.user_id]
}
}).exec(function (err, teamProfiles) {

var asyncTasks = [];

teamProfiles.forEach(function (teamProfile) {
asyncTasks.push(function (callback) {
UserProfile.find({
UserID : {
$in : teamProfile.Members.map(function (id) {
return id;
})
}
}, function (err, userProfiles) {
teamProfile.Members = userProfiles;
callback();
})
});
});

teamProfiles.forEach(function (teamProfile) {
asyncTasks.push(function (callback) {
Draft.find({
_id : {
$in : teamProfile.Drafts.map(function (id) {
return id;
})
}
}, function (err, drafts) {
teamProfile.Drafts = drafts;

drafts.forEach(function (draft) {
Comment.find({
_id : {
$in : draft.Comments.map(function (id) {
return id;
})
}
}).exec(function (err, comments) {
draft.Comments = comments;
callback();
//This is where the callback should be called
//Throws Error: Callback was already called.
})
})

})
});
});

async.parallel(asyncTasks, function () {
res.json(teamProfiles)
});
});
})


I am using
async.parallel()
to perform all the queries. I am very new to all of this so please excuse some beginner mistakes.

Answer

You are iterating over drafts synchronously and calling async's callback function on the first item. Getting an error when you try to call it again with the second item is expected behaviour.

You should instead call the done callback once you have finished all the draft queries, not for each one. Since you are using async, you could nest another async.each to handle this:

router.route('/teams/:user_id').get(function (req, res) {

        TeamProfile.find({
            Members : {
                $in : [req.params.user_id]
            }
        }).exec(function (err, teamProfiles) {

            var asyncTasks = [];

            teamProfiles.forEach(function (teamProfile) {

                asyncTasks.push(function (callback) {
                    UserProfile.find({
                        UserID : {
                            $in : teamProfile.Members.map(function (id) {
                                return id;
                            })
                        }
                    }, function (err, userProfiles) {
                        teamProfile.Members = userProfiles;
                        callback();
                    });
                });
            });

            teamProfiles.forEach(function (teamProfile) {
                asyncTasks.push(function (callback) {
                    Draft.find({
                        _id : {
                            $in : teamProfile.Drafts.map(function (id) {
                                return id;
                            })
                        }
                    }, function (err, drafts) {
                        teamProfile.Drafts = drafts;

                        async.each(drafts, function(draft, draftCallback){

                            Comment.find({
                                _id : {
                                    $in : draft.Comments.map(function (id) {
                                        return id;
                                    })
                                }
                            }).exec(function (err, comments) {
                                draft.Comments = comments;
                                draftCallback();
                            });

                        }, function(err){
                            callback();
                        });
                    });
                });
            });

            async.parallel(asyncTasks, function () {
                res.json(teamProfiles)
            });
        });
    });
Comments