0

I want to query two separate and different things to mongodb using Mongoose and ajax asynchronously.

Here is the code:

var teams, faculties;
userModel.find({}).sort('-score').exec((err, result) => {
        teams = result;
    });

    userModel.aggregate([{
        "$group": {
            _id: "$faculty",
            average: {
                $avg: "$score"
            }
        }
    }]).exec((err, result) => {
        faculties = result;
    });
res.render('/scoreboard', {
    information: [teams, faculties]
})

Is there a better implementation to handle the queries to run asynchronously?

3
  • 1
    This will fail, because it tries to call res.render synchronously, before the database calls have returned. To fix this, move the res.render part inside the second callback. Better yet, rewrite it so that the two calls to the database run in parallel. Since they're done using callbacks, you could use an npm library called async to combine them. Alternatively, you could wrap them in promises and use Promise.all to combine them. Commented Sep 3, 2018 at 21:57
  • @DavidKnipe Would you give me some hints about how to implement? Thank you for your helpful comment. Commented Sep 3, 2018 at 22:01
  • These two methods of calling the banks are within a function? Within a request, response? I need more code to come up with the answer for you. Commented Sep 3, 2018 at 22:17

2 Answers 2

1

Using async/await we eliminate the callbacks and leave the calls independent. The error trait can also be simplified by placing if with negation conditions.

app.get('/myroute', async(req, res) => {
    try {
        const teams = await userModel.find({}).sort('-score')
        const faculties = await userModel.aggregate([{
            "$group": {
                _id: "$faculty",
                average: {
                    $avg: "$score"
                }
            }
        }])    
        res.render('/scoreboard', { information: [teams, faculties] })

    } catch (error) {
        res.status(400).send(error)
    }
})
Sign up to request clarification or add additional context in comments.

4 Comments

@Li357 Thanks, in case I did a simple treatment, but in the case of async it would be necessary several try, one on each call to the bank, or receive the error with destructuring.
It doesn't work properly when I console.log(teams) it returns a string of data that sounds ambiguous to me
@MostafaGhadimi Could you add that result to the question? For me to analyze. I think it has to do with sort (). The find must be returning all data.
This will make the two database calls run in series. If you want them to run in parallel using the async/await syntax, try this: const teamsPromise = userModel.find({}).sort('-score'); const facultiesPromise = userModel.aggregate( ... ); const teams = await teamsPromise; const faculties = await facultiesPromise; res.render('/scoreboard', { information: [teams, faculties] });.
0

Another improvement that can be made is to run it parallely using Promise.all because those functions are independent each other.

app.get('/myroute', async(req, res) => { 
    const response = await Promise.all([
      userModel.find({}).sort('-score'),
      userModel.aggregate([{
          "$group": {
              _id: "$faculty",
              average: {
                  $avg: "$score"
              }
          }
      }])    
    ]); // response will return as [teams, faculties]
    res.render('/scoreboard', { information: response })
})

5 Comments

Promise.all doesn't magically have promises run "parallely"... promises run like they normally do-asynchronously and Promise.all just combines them into a single promise that resolves when all of them resolve...
@Li357 good feedback, I may have used wrong word to describe that. Thanks.
@Li357 you mean that it doesn't work asynchronously?
@deerawan it works but how can I access average of them? when I console.log(response) it contains the data of userModel.find({}) and an array of objects: i.sstatic.net/7v1XT.png
Li357 wasn't very clear about this: "Promise.all doesn't magically have promises run \"parallely\"" - I don't think they meant to say that it won't run in parallel. Both asynchronous tasks will start at almost the same time, and they'll run in parallel. Probably Li357 meant that they would have run in parallel even if you hadn't wrapped them inside Promise.all[ ... ]).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.