Bahman.A
Bahman.A

Reputation: 1296

Create an object or associative array with elements of an existing array and the result of a callout for each element

This is in the context of a node express route. I receive a get request with a query param that is a list of IDs. Now I need to make a call-out for each ID and store the result of the callout in an array or object. Each element of the first array (containing the IDs) need to be mapped to its corresponding result from the call-out. I don't have a way to modify the endpoint that I'm hitting from this route so I have to make single calls for each ID. I've done some research and so far I have a mixture of code and sudo code like this:

const ids = req.query.ids;
const idMembers = Promise.all(ids.map(async id => { 
  // here I'd like to create a single object or associative array
  [ id: await callout(id); ]
}));

When all promises resolved I need the final result of idMembers to be like: (The response will be an object with nested arrays and objects I've just simplified it for this post but I need to grab that from the res.payload)

{
  '211405': { name: 'name1', email: '[email protected]' },
  '441120': { name: 'name2', email: '[email protected]' },
  '105020': { name: 'name3', email: '[email protected]' }
}

Oh and of course I need to handle the callout and the promise failures and that's when my lack of experience with javascript becomes a real issue. I appreciate your help in advance!!

Some extra thought I'm having is that I'd have to map the results of the resolved promises to their id and then in a separate iteration I can then create my final array/object that maps the ids to the actual payloads that contain the object. This is still not answering any of my questions though. I'm just trying to provide as much information as I've gathered and thought of.

Upvotes: 0

Views: 57

Answers (1)

Vitalii
Vitalii

Reputation: 2131

Promise.all returns an array of results (one item per each promise).

Having this temporary structure it is possible to build the needed object.

const arrayOfMembers = Promise.all(ids.map(async id => { 
  // ...
  return { id, value: await callout(id) } // short syntax for { id: id, value: ... } (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer)
}));
// arrayOfMembers = [
//  { id: 211405, value: { name: 'name1', email: '[email protected]' } },
// ...
// ]

In pure JS it can be done with for loop or .forEach() call to iterate:

const res = {};
arrayOfMembers.forEach(el => {
  const { id, value } = el;
  res[el] = value;
});

or by using a single reduce() call

const res = arrayOfMembers.reduce((accumulator, el) => {
   const { id, value } = el;
   return { ...accumulator, [id]: value };
}, {});

in both cases res will be:

// res = {
//   '211405': { name: 'name1', email: '[email protected]' },
// ...
// }

P.S.

There is a handy library called lodash. It has tons of small methods for data manipulation.

For example, _.fromPairs() can build an object from [[key1, value1], [key2, value2]] pairs.

As you mentioned you have lodash, so I think the following should work:

const arrayOfKeyValuePairs = Promise.all(ids.map(async id => { 
  // ...
  return [ id, await callout(id) ] // array here so it matches what fromPairs needs
}));
const res = _.fromPairs(arrayOfKeyValuePairs);

Upvotes: 1

Related Questions