1

I have three queries on Firestore based on a time range. (24, 12 and 6 hour). I am using Promise.all and it works. As you can see from the code, I am accessing the result of each query by using an index to the returned snapshot. I have read that the Returned values will be in the order of the Promises passed, regardless of completion order.

Now, I want to be able to pass an object to the Promise.all because my number of queries will be unpredictable for what I want to do, basically, I will be looping to a number of vehicles and building the same 3 queries for each and I will pass it all on a Promise.all. And when Promise.all returns, I want to be able to know which vehicle and time range that snapshot is for.

So instead of an array, I want to pass this argument to Promise.all instead.

{"vehicle1_24":query, "vehicle1_12":query, "vehicle1_6":query,
"vehicle2_24":query, "vehicle2_12":query, "vehicle2_6":query}

code

var queries = [
        vehicleRef.collection('telemetry').where('time_stamp', '<', today).where('time_stamp', '>', yesterday).get(),
        vehicleRef.collection('telemetry').where('time_stamp', '<', today).where('time_stamp', '>', twelveHours).get(),
        vehicleRef.collection('telemetry').where('time_stamp', '<', today).where('time_stamp', '>', sixHours).get()
      ]

      for (var i = 0; i < queries.length; i++) {
        queryResults.push(
          queries[i]
        )
      }

      Promise.all(queryResults)
        .then(snapShot=> {

          const yesterdayResult = result => getEnergy(result);
          const twelveHourResult = result => getEnergy(result);
          const sixHourResult = result => getEnergy(result);

          allYesterdayResult += yesterdayResult(snapShot[0])
          allTwelveHourResult += twelveHourResult(snapShot[1])
          allSixHourResult +=sixHourResult(snapShot[2])


          console.log("Done updating vehicle ", vehicle)
          // return res.send({"Result" : "Successful!"})
        }).catch(reason => {
          console.log(reason)
          // return res.send({"Result" : "Error!"})
ellaRT
  • 1,346
  • 2
  • 16
  • 39
  • `Promise.all()` needs an array. If you want to wait for a bunch of promises that are all properties on an object, then you have to extract all those promises from the object and put them in an array so you can call `Promise.all()` with the array. You can make a function `Promise.allObject()` that does that for you if you want. – jfriend00 Apr 24 '18 at 04:56
  • FYI, the [Bluebird promise library](http://bluebirdjs.com/docs/api/promise.props.html) has `Promise.props()` that sounds like it might do what you want. – jfriend00 Apr 24 '18 at 04:59
  • what do you mean by creating my own `allObject()`? @jfriend00 – ellaRT Apr 24 '18 at 05:35
  • 1
    I mean you create your own function to do what you're asking for. It would be a function that extracts promises from properties on an object, puts them in an array, calls `Promise.all()` on them all, when `Promise.all()` resolves, then it processes the results however you want and returns that as the resolved value. Just make your own function that accepts the object you want to pass in and then converts the data to the right form to use `Promise.all()` because you can't pass the object to `Promise.all()` directly. – jfriend00 Apr 24 '18 at 05:46

1 Answers1

6

This feature does not exist natively, but should be fairly easy to write, something along the lines of

async function promiseAllObject(obj) {
  // Convert the object into an array of Promise<{ key: ..., value: ... }>
  const keyValuePromisePairs = Object.entries(obj).map(([key, valuePromise]) =>
    valuePromise.then(value => ({ key, value }))
  );

  // Awaits on all the promises, getting an array of { key: ..., value: ... }
  const keyValuePairs = await Promise.all(keyValuePromisePairs);

  // Turn it back into an object.
  return keyValuePairs.reduce(
    (result, { key, value }) => ({ ...result, [key]: value }),
    {}
  );
}

promiseAllObject({ foo: Promise.resolve(42), bar: Promise.resolve(true) })
  .then(console.log); // { foo: 42, bar: true }
Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308