0

I would like to iterate thru each of the students and then excecute two query which the execution of these two queries should be sync, first one first then since the second query depends on the first.

I have written some code but it does not seem working at all:

Student.find({ status: 'student' })
    .populate('student')
    .exec(function (err, students) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        }

        _.forEach(students, function (student) {
            async.waterfall(
                [
                    function (callback) {
                        console.log('first ' + student.firstName);
                        Student.find({ "_id": student.id }, callback);
                    },
                    function (student, callback) {
                        console.log('second '+ student[0].firstName);
                        WorksnapsTimeEntry.find({
                            "student": {
                                "$in": student.map(function (el) {
                                    return el._id
                                })
                            }
                        }, callback);
                    }
                ],
                function (err, results) {
                    if (err) {
                        // do something
                    } else {
                        // results are the matching entries
                        console.log('third');
                        var totalMinutes = 0;
                        var totalAvgLevelActivity = 0;
                        var counter = 0;
                        _.forEach(results, function (item) {
                            _.forEach(item.timeEntries, function (item) {
                                if (item.duration_in_minutes) {
                                    totalMinutes = totalMinutes + parseFloat(item.duration_in_minutes[0]);
                                }

                                if (item.activity_level) {
                                    totalAvgLevelActivity = totalAvgLevelActivity + parseFloat(item.activity_level[0]);
                                    counter++;
                                }
                            });
                        });

                        var obj = {};
                        obj.studentId = 'test';
                        obj.firstName = 'test';
                        obj.lastName = 'test';
                        obj.municipality = 'test';
                        obj.totalMinutes = totalMinutes;
                        obj.totalAvgLevelActivity = totalAvgLevelActivity / counter;
                        arrayReports.push(obj);
                        // console.log('not yet finished.');
                    }
                }
            );
        });

        res.json(arrayReports);
        console.log('finished.');

Anyone has an idea how do I achieve this thing in Node.js

3
  • do you get any output ? Commented Apr 24, 2016 at 4:11
  • Yes, I can see students first name printed but I am not quit sure if they are printed in that way that first student has to be finished with everything untill second student starts... also res.json(arrayReports) is always null as of course it is being executed before those queryes within foreach are finished, is there any way that I can wait till all finished then execute res.json() Commented Apr 24, 2016 at 4:15
  • I guess you are using the async.waterfall wrong. From each of the task functions, you need to call the next function with suitable arguments Commented Apr 24, 2016 at 4:31

1 Answer 1

2

mongoose is promisified, you don't have to use async to handle the flow nor lodash for a simple forEach. And your find by _id request is useless, you already have a Student object:

Student.find({ status: 'student' })
    // .populate('student') // why this?
    .then(function (students) {
        // build an array of promises
        var promises = students.map(function (student) {
            return WorksnapsTimeEntry.find({
                "student": student._id;
            });
        });

        // return a promise to continue the chain
        return Promise.all(promises);
    }).then(function(results) {
        // results are the matching entries
        console.log('third');
        var totalMinutes = 0;
        var totalAvgLevelActivity = 0;
        var counter = 0;
        _.forEach(results, function (item) {
            _.forEach(item.timeEntries, function (item) {
                if (item.duration_in_minutes) {
                    totalMinutes = totalMinutes + parseFloat(item.duration_in_minutes[0]);
                }

                if (item.activity_level) {
                    totalAvgLevelActivity = totalAvgLevelActivity + parseFloat(item.activity_level[0]);
                    counter++;
                }
            });
        });

        var obj = {};
        obj.studentId = 'test';
        obj.firstName = 'test';
        obj.lastName = 'test';
        obj.municipality = 'test';
        obj.totalMinutes = totalMinutes;
        obj.totalAvgLevelActivity = totalAvgLevelActivity / counter;
        arrayReports.push(obj);
        // console.log('not yet finished.');
        res.json(arrayReports);
        console.log('finished.');
    }).catch(function(err) {
        return res.status(400).send({
            message: errorHandler.getErrorMessage(err)
        });
    });
Sign up to request clarification or add additional context in comments.

1 Comment

awesome, nice, clean and most importantly, workable :) thnx

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.