1

Hello I have an API call getItems() that return data like this :

[
 {
   name: 'item1',
   materials: [
     1,
     2,
     3,
   ],
 },
 {
   name: 'item2',
   materials: [
     2,
     3,
     6,
   ],
 }
 ...
]

And another API call getMaterial(id) that return the data of a material like this :

{
  name: 'mat1',
  img: '/img.jpg'
}

What I'm try to achieve is to get all the items data with the materials data. I manage to have all the observable call for materials but I don't know what to do after.

That's what I've done so far :

public getAllItemsData(): Observable<any> {
  return getItems().pipe(
    map((list: items[]) => {
      return list.map(item => {
        const allMat = item.materials.map(m => getMaterial(m))

        return forkJoin(allMat).pipe(
          map(data => {
            return {
              ...item,
              materials: data
            }
          })
        )
      })
    }),
  );
}

But it's not working. Thank for the help.

3 Answers 3

2

Try this. Using switchMap, mergeMap, from, forkJoin

getItems()
  .pipe(
    switchMap((items) =>
        // for each items
      from(items).pipe(
       // merge map to run parallel for each items
        mergeMap(({ materials, ...item }) =>
        // wait to retrive all materials details of current item at mergeMap
        // after completing use map to map item with retrived materials 
          forkJoin(
            materials.map((m) => this.getMaterial(m))
          ).pipe(map((materialDetails) => ({ ...item, materials: materialDetails })))
        )
      )
    )
  )
  .subscribe((result) => {
    console.log(result);
  });
Sign up to request clarification or add additional context in comments.

5 Comments

Is there a way to do it without switchMap, to make it easier (I shouldn't have) I ommit the point that I'm using firestore valuechange which mean there is an active stream and I feel like the switchMap causing problems in this solution ! I have no errors, but I have no output data.
If You can generate on stackblitz. I can help you easily
error Can't find package:@angular/fire.. Can you share some JSON data instead? Or should i come up with demo example with data from question?
1

Very similar to the above just with less nested pipes

interface Item {
    name: string;
    materials: number[];
}

interface MaterialData {
    name: string;
    img: string;
}

public getAllItemsData() {
    return getItems().pipe(
        switchMap((items: Item[]) => from(items)), // use 'from' to deal with one Item at a time
        mergeMap(({ materials, name }: Item) =>
            forkJoin(materials.map((mat) => getMaterial(mat))) // create array of observables using map, and pass into forkJoin 
                .pipe(
                    map((materials) => ({ name, materials })), // reconstruct object
                ),
        ),
        toArray(), // collect all emissions and output as an array
    );
};

1 Comment

Is there a way to do it without switchMap, to make it easier (I shouldn't have) I ommit the point that I'm using firestore valuechange which mean there is an active stream and I feel like the switchMap causing problems in this solution ! I have no errors, but I have no output data
0

I think you're just missing a final merge/forkJoin to subscribe to the array of observables you've created.

public getAllItemsData(): Observable<any> {

  return getItems().pipe(

    map((list: items[]) => 
      list.map(item => 
        forkJoin(
          item.materials.map(m => getMaterial(m))
        ).pipe(
          map(materials => ({
            ...item,
            materials
          }))
        )
      )
    ),

    // Subscribe to the list created above
    mergeMap((list:Observable<any>[]) => forkJoin(list))

  );

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.