Albert
Albert

Reputation: 76

Filtering results of Promise.all

I'm chaining a series of Promises to operate with a database. From a first Promise, I retrieve an array of objects. In the second Promise, I generate a Promise for each object. Then, I filter the results. Here is a code example:

db.getUser(user)
  .then(user=> Promise.all(
    user.shirts.map(userShirt => db.getShirt(shirt.id))
  ) as Promise<IShirt[]>)
  .then(shirts => {
    shirts = shirts.filter(shirt => shirt.color === 'blue');
    console.log(shirts);
  })
  .catch(err => {
      console.log(err);
  });

This is a simplified example of what my code does. The problem is in the filter operation where I retrive a 0 lenght array. Any idea?

Upvotes: 1

Views: 190

Answers (2)

richytong
richytong

Reputation: 2452

This is how you fix the filter operation when you retrieve a 0 length array.

One of your variable names is off:

db.getUser(user)
  .then(user=> Promise.all(
    user.shirts.map(userShirt => db.getShirt(shirt.id)) // <- perhaps you meant `userShirt.id` here?
  ))
  .then(shirts => {
    shirts = shirts.filter(shirt => shirt.color === 'blue')
    console.log('shirts')
  })
  .catch(err => {
    console.error(err),
  })

You could be fine with that, though the bigger issue here is having to worry about Promise.all in the first place. I wrote a library so you wouldn't have to worry about boilerplate Promise code.

Below is code equivalent to your example written with functions pipe, map, filter, get, and eq from my library:

const db = {} // your db instance here

const getBlueShirts = pipe([
  db.getUser,
  get('shirts'),
  map(pipe([get('id'), db.getShirt])),
  filter(eq('blue', get('color'))),
])

tryCatch(getBlueShirts, console.error)(user)

further, you could map and filter in one fell swoop by using transform. When you use transform, map(...) and filter(...) become transducers composed with pipe.

const getBlueShirts = pipe([
  db.getUser,
  get('shirts'),
  transform(pipe([ // pipe([map(...), filter(...)]) is a transducer
    map(pipe([get('id'), db.getShirt])),
    filter(eq('blue', get('color'))),
  ]), [])
])

I write more about transducers here

Upvotes: 0

danh
danh

Reputation: 62676

Collect the promises produced by the calls to getShirt, then run them together. Promise all will produce an array of the resolutions of those promises.

EDIT I see that you do have a Promise.all in the OP. The simple solution is to fix the undefined temp variable name:

user.shirts.map(userShirt => db.getShirt(shirt.id)) // shirt is undefined
user.shirts.map(userShirt => db.getShirt(userShirt.id))

Upvotes: 1

Related Questions