Rodrigo Villalobos
Rodrigo Villalobos

Reputation: 197

How to execute multiple mongoose queries asynchronously and wait until all of them finish executing before sending response?

Thanks in advance, but could someone explain to me how can I execute a different query for each property of my request? I am trying to create a search sidebar menu, when user changes checkbox values I create an object with these properties:

    {
      "category": [
        "electronics",
        "clothing",
        "pets"
      ],
      "condition": [
        "old",
        "new"
      ]
    }

I want to push a query into an array of functions and then execute them using async.parallel When called i want to push the result of each query inside one array containing the result of all queries.

router.get('', async function(req,res)
{
    var searchResults = [];
    if(req.query.filters)
    {

        const queryObj = JSON.parse(req.query.filters);
        var searchQueries = [];
        if(queryObj.category){
            searchQueries.push(async function (cb) {
                return await Rentals.find({/* SOME CONDITION */}).populate('-something').exec(function (err, docs) {
                    if (err) {
                        throw cb(err);
                    }

                    cb(null, docs);
                });
            })    
        }

        if(queryObj.condition){
            searchQueries.push(async function (cb) {
                return await Rentals.find({/* SOME CONDITION */}).populate('-something').exec(function (err, docs) {
                    if (err) {
                        throw cb(err);
                    }

                    cb(null, docs);
                });
            })    
        }


        async.parallel(searchQueries, function(err, foundRentals) {
            if (err) {
                throw err;
            }
            searchResults.push(foundRentals[0]); // result of searchQueries[0]
            searchResults.push(foundRentals[1]); // result of searchQueries[1]
            searchResults.push(foundRentals[2]); // result of searchQueries[2]

        })
    }
    res.json(searchResults);
});

The problem comes when returning searchResults, I am receiving an empty array from the server however after the response was sent the queries finish and I get the result AFTER response was sent. How can I execute all queries at the same time and wait until all of them finish before sending a response to client?

Upvotes: 0

Views: 1311

Answers (2)

Rodrigo Villalobos
Rodrigo Villalobos

Reputation: 197

I solved it using this syntaxis

let finalResults = await Promise.all(arrayToIterate.map(async(value) => { // map instead of forEach
    const result = await getRentalsByQuery({query});
    finalValue = result;
    return finalValue; // important to return the value
}));

Upvotes: 1

Cody Geisler
Cody Geisler

Reputation: 8617

Your promise.all code version would look something like this:

router.get('', async function(req,res)
{
    try{
        let searchResults = [],
            categoryPromises = [],
            conditionPromises = [];

        if(req.query.filters)
        {

            const queryObj = JSON.parse(req.query.filters);
            if(queryObj.category && queryObj.category.length > 0){
                categoryPromises = queryObj.category.map(singleCategory=>{
                    return Rentals
                        .find({/* SOME CATEGORY? */})
                        .populate('-something')
                        .exec();
                });   
            }

            if(queryObj.condition && queryObj.condition.length > 0){
                conditionPromises = queryObj.category.map(singleCondition=>{
                    return Rentals
                        .find({/* SOME CONDITION */})
                        .populate('-something')
                        .exec();
                });   
            }

            searchResults.push(await categoryPromises);
            searchResults.push(await conditionPromises);

        }
        res.json(searchResults);
    }catch(e){
        // catch-all error handling here
    }
});

(instead of .map you could also use a for-loop to push them into a categoryPromises array)

Upvotes: 1

Related Questions