0

I am running multiple aggregate queries using Mongoose and need to have access to the results of these aggregate queries in the same place for the purposes of my application logic.

One thing I need to compute is the mean of a field in a collection and another is the standard deviation.

Company.aggregate([{ $group: { _id: null, mean: {$avg: '$customers'}}}])

Company.aggregate([{ $group: { _id: null, std: {$stdDevPop: '$customers'}}}])

I know I can run exec on both of these individually and use the then() method to acquire the results individually, but how would I go about getting access to these together and then using both of these results together. I guess my question is more about promises more than anything. Is there a way to put the two queries above into an array and then executing a function once both of those promises in the array are resolved?

Is there a way to combine promises so that I can run then() off of the combined promise?


Edit:

let q1 = Company.aggregate([{ $group: { _id: null, mean: {$avg: '$customers'}}}]),
let q2 = Company.aggregate([{ $group: { _id: null, std: {$stdDevPop: '$customers'}}}]),
    queries = [q1, q2].map(q=>q.exec());

Promise.all(queries)
  .then((results)=>{
     const averageCustomers = results[0][0].mean;
     const companies = Company.find({ customers: { $lt: averageCusomters } });
     return companies.exec();
  })
  .then((results)=>{
    //here I only have access to the companies that have less than average customers. 
    //I no longer have access to the average customers across 
    //all companies or their standard deviation.
  })
J. Stott
  • 41
  • 5

1 Answers1

0

You are looking for something like Promise.all(). You will get results from all the queries in an array(results).

let q1 = Company.aggregate([{ $group: { _id: null, mean: {$avg: '$customers'}}}]),
    q2 = Company.aggregate([{ $group: { _id: null, std: {$stdDevPop: '$customers'}}}]),
    queries = [q1, q2].map(q=>q.exec());

Promise.all(queries)
.then((results)=>{
   console.log(results)
})
dasfdsa
  • 7,102
  • 8
  • 51
  • 93
  • Awesome! This is exactly what I was looking for. I was wondering, will the results array always be populated in the order that its respective queries are specified in the queries array or will it be populated according to when the various promises were resolved? i.e. will the results array always return the results of q1 followed by q2 in the example your provided? – J. Stott Aug 20 '18 at 10:58
  • Promise.all will do that work for you and populate `results` according to the order of `queries` array. So effectively, you don't have to worry about the order in which promises have resolved. – dasfdsa Aug 20 '18 at 11:02
  • Thanks! I have another question if you don't mind. I want to run the above aggregate functions and then run another query based on the results of one of these aggregate queries. Basically I want to run another query that gets all companies with less than average customers. I then want to have access to not only the companies with less than average customers but also the average value also but I am struggling to pass both of these through to the next `.then()` method. Any ideas on how to do this? – J. Stott Aug 20 '18 at 11:21
  • I added some extra details to the original question so you know what I mean. – J. Stott Aug 20 '18 at 11:29
  • Yeah thats a common problem with `.then()`. see [here](https://stackoverflow.com/questions/28250680/how-do-i-access-previous-promise-results-in-a-then-chain). async/await solves it beautifully. If you are using latest node version prefer that. – dasfdsa Aug 20 '18 at 12:38
  • You're a star!! Thank you so much for all of your help :) – J. Stott Aug 20 '18 at 15:05