undefined
undefined

Reputation: 3632

Map Promise.all output with promises index

I am using nodejs v8+ which supports default async await style of code.

In my problem, I am trying to push all the promises into an array and then use Promise.all to with await keyword to get the responses. But the problem is, I am not able to map the promises with the keys.

Here is the example:

let users = ["user1", "user2", "user3"];

    let promises = [];
    for(let i = 0; i < users.length; i++){
      let response = this.myApiHelper.getUsersData(users[i]);
      promises.push(response);
    }
    let allResponses = await Promise.all(promises);

Here I get all the collected response of all the responses, but I actually want to map this by user. For example currently I am getting data in this format:

[
{
  user1 Data from promise 1
},
{
  user2 Data from promise 2
},
{
  user3 Data from promise 3
}
]

But I want data in this format:

[
 {
  "user1": Data from promise 1
 },
 {
   "user2": Data from promise 2
 },
 {
   "user3": Data from promise 3
 }
]

I am sure there must be a way to map every promise by user, but I am not aware of.

Upvotes: 4

Views: 9598

Answers (3)

Orelsanpls
Orelsanpls

Reputation: 23515

We are going to create an array of user. Iterate over it to create an array of Promise we give to Promise.all. Then iterate on the answer to create an object that's matching the user with the associated answer from getUsersData.

Something to know about Promise.all is that the order of the returned data depends on the order of the promises given in entry of it.

const users = ['user1', 'user2', 'user3'];

const rets = await Promise.all(users.map(x => this.myApiHelper.getUsersData(x)));

const retWithUser = rets.map((x, xi) => ({
   user: users[xi],
   ret: x,
}));

Here you have a great tutorial about Array methods (map, filter, some...).

Upvotes: 8

undefined
undefined

Reputation: 3632

Though the answer accepted by me is one of the solution, which I think is perfect and I will keep as accepted answer but I would like to post my solution which I figured out later which is much simpler:

We could simply use this:

let finalData = {};
let users = ["user1", "user2", "user3"];
await Promise.all(users.map(async(eachUser) => {
    finalData[user] = await this.myApiHelper.getUsersData(eachUser);
}))
console.log(finalData);

Upvotes: 3

cbh6
cbh6

Reputation: 149

as described here How to use Promise.all with an object as input

Here is a simple ES2015 function that takes an object with properties that might be promises and returns a promise of that object with resolved properties.

function promisedProperties(object) {

  let promisedProperties = [];
  const objectKeys = Object.keys(object);

  objectKeys.forEach((key) => promisedProperties.push(object[key]));

  return Promise.all(promisedProperties)
    .then((resolvedValues) => {
      return resolvedValues.reduce((resolvedObject, property, index) => {
        resolvedObject[objectKeys[index]] = property;
        return resolvedObject;
      }, object);
    });

}

And then you will use it like so:

var promisesObject = {};
users.map((element, index) => object[element] = this.myApiHelper.getUsersData(users[index]));
promisedProperties(object).then(response => console.log(response));

Note that first of all you need an object with key/promise.

Upvotes: -1

Related Questions