Mjuice Mjuice - 5 months ago 13
Node.js Question

In an API endpoint using Mongoose and MongoDB, how do I wait for all database queries to finish before returning a response to the client

I'm writing an API endpoint that calculates a user's total revenue for each day of the past 7 days.

I use the mongoose .find({}) method to query the database 8 times. After all 8 .find({}) calls return, I want to send a response to the client. Should I just chain all the .find({}) calls with .then functions which call the next .find({}), or is there a simpler way to wait for all queries to finish?

Here is what my route looks like minus a few of the .find({}) calls for the sake of brevity:

app.get('/loadThisWeeksRevenue/:userId', function(req, res, next) {

//todays date info using momentjs
var startOfToday = moment().startOf('day');
var endOfToday = moment().endOf('day');
var oneDayAgo = moment(startOfToday).subtract(1, 'days');
var twoDaysAgo = moment(startOfToday).subtract(2, 'days');
var threeDaysAgo = moment(startOfToday).subtract(3, 'days');
var fourDaysAgo = moment(startOfToday).subtract(4, 'days');
var fiveDaysAgo = moment(startOfToday).subtract(5, 'days');
var sixDaysAgo = moment(startOfToday).subtract(6, 'days');
var sevenDaysAgo = moment(startOfToday).subtract(7, 'days');

//set variables for the past 7 days revenue
var sevenDaysAgoRevenue = 0;
var sixDaysAgoRevenue = 0;
var fiveDaysAgoRevenue = 0;
var fourDaysAgoRevenue = 0;
var threeDaysAgoRevenue = 0;
var twoDaysAgoRevenue = 0;
var oneDayAgoRevenue = 0;
var todaysRevenue = 0;


//Calculate 7 days ago revenue
Sale
.find({ owner: req.params.userId, created_at: {$gte: sevenDaysAgo, $lt: sixDaysAgo} })
.exec(function(err, sales) {

if (err) { return next(err); } //check for error

sales.map(sale => {
sevenDaysAgoRevenue += sale.total;
});

});

//Calculate 6 days ago revenue
Sale
.find({ owner: req.params.userId, created_at: {$gte: sixDaysAgo, $lt: fiveDaysAgo} })
.exec(function(err, sales) {

if (err) { return next(err); } //check for error

sales.map(sale => {
sixDaysAgoRevenue += sale.total;
});

});



//Calculate 1 day ago revenue
Sale
.find({ owner: req.params.userId, created_at: {$gte: oneDayAgo, $lt: startOfToday} })
.exec(function(err, sales) {

if (err) { return next(err); } //check for error

sales.map(sale => {
oneDayAgoRevenue += sale.total;
});

});

//Calculate today's revenue
Sale
.find({ owner: req.params.userId, created_at: { $gte: startOfToday, $lt: endOfToday}})
.exec(function(err, sales) {

if (err) { return next(err); } //check for error

sales.map(sale => {
todaysRevenue += sale.total;
});

});

var dataRowsForWeeksRevenue = [
[new Date(sevenDaysAgo), sevenDaysAgoRevenue],
[new Date(sixDaysAgo), sixDaysAgoRevenue],
[new Date(fiveDaysAgo), fiveDaysAgoRevenue],
[new Date(fourDaysAgo), fourDaysAgoRevenue],
[new Date(threeDaysAgo), threeDaysAgoRevenue],
[new Date(twoDaysAgo), twoDaysAgoRevenue],
[new Date(oneDayAgo), oneDayAgoRevenue],
[new Date(), todaysRevenue]
];

res.status(200).json(dataRowsForWeeksRevenue);

});

Tim Tim
Answer

You can use async package.

Example:

async.parallel([
    function(callback){ ... },
    function(callback){ ... }
], function(err, results) {
    // optional callback
};

In your case:

async.parallel([
    function(callback){ 

        Sale
        .find({ owner: req.params.userId, created_at: {$gte: sevenDaysAgo, $lt: sixDaysAgo} })
        .exec(function(err, sales) {

            if (err) { return callback(err); } //check for error

            sales.map(sale => {
                sevenDaysAgoRevenue += sale.total;
            });

            callback();
        });

},
    function(callback){ 
        Sale
        .find({ owner: req.params.userId, created_at: {$gte: sixDaysAgo, $lt: fiveDaysAgo} })
        .exec(function(err, sales) {

            if (err) { return callback(err); } //check for error

            sales.map(sale => {
                sixDaysAgoRevenue += sale.total;
            });

            callback();

        });

}
], function(err, results) {
    var dataRowsForWeeksRevenue = [
            [new Date(sevenDaysAgo), sevenDaysAgoRevenue],
            [new Date(sixDaysAgo), sixDaysAgoRevenue],
            [new Date(fiveDaysAgo), fiveDaysAgoRevenue],
            [new Date(fourDaysAgo), fourDaysAgoRevenue],
            [new Date(threeDaysAgo), threeDaysAgoRevenue],
            [new Date(twoDaysAgo), twoDaysAgoRevenue],
            [new Date(oneDayAgo), oneDayAgoRevenue],
            [new Date(), todaysRevenue]
        ];

        res.status(200).json(dataRowsForWeeksRevenue);
};
Comments