amerej
amerej

Reputation: 139

Chaining rxjs 6 observables with nested array

I have to do 3 dependent request to an API.

  1. The first retreive an array of user id's.
  2. The second have to iterate over the user id's array and for each retreive an array of project id's related to the user.
  3. The third have to iterate over the project id's array and retreive data related to projects.

I want this kind of result:

[{'username': 'richard', projects: [{"id": 1, "name": "test"}]}, ...]

But i'm totally stuck with mergeMap, forkJoin etc..

The thing i have tried:

getUserTeamMembers(): Observable<any> {
return this.http.get(`${environment.serverUrl}/user/profil`).pipe(
  mergeMap((teamUsers: any) =>
    this.http.get(
      `api/user/${teamUsers.data._id}/team`
    )
  ),
  mergeMap((teamUsers: any) =>
    forkJoin(
      ...teamUsers.data.map((user: any) =>
        this.http.get(`api/user/${user.id}`)
      )
    )
  ),
  map((res: any) =>
    res
      .map((user: any) => {
        if (user.data) {
          return {
            firstname: user.data.local.firstname,
            lastname: user.data.local.lastname,
            email: user.data.local.email,
            projects: user.data.local.projects,
            language: user.data.local.lang
          };
        }
      })
      .filter((user: any) => user !== undefined)
  ),
  tap(t => console.log(t)),
  catchError(err => throwError(err))
);}

I try so many things, but i have no clue where to populate my array of projects which is currently only contains id's, not data related:

[{'username': 'richard', projects: ['id1', 'id2']}, ...]

Upvotes: 2

Views: 407

Answers (1)

Louay Al-osh
Louay Al-osh

Reputation: 3415

have made a similar example hope it clear the idea.

of course did't use http instead made it local using of

and stored the final result in an array called results

we have a source to get the list of all users, another source that given the user id it will return the list of this user's projects' ids projectList, and finally a source that give one project id will returns it's details(projcectsDetails)

    let users = of([ 1, 2, 3 ])
    let projectsList = (userId) => of([ userId, userId*2 ]) 
    let projectsDetails = (projectId) => of({ id: projectId, details: `details about ${projectId}` })


    let results = [];

    users
    .pipe(
      tap(users => {
        users.forEach(userId => results.push({ userId, projects: [] }));

        return users
      }),
      switchMap(users => forkJoin(users.map(userId => projectsList(userId)))),
      switchMap(projectsArray => forkJoin(
          projectsArray.map(
            oneProjectArray => 
            forkJoin(oneProjectArray.map(projectId => projectsDetails(projectId)))
          )
        )
      ),
      tap(projectDetailsArray => {
        projectDetailsArray.forEach((projectsArray, index) =>{
          results[index]['projects'] = [ ...projectsArray ]
        })
      })
    )
    .subscribe(() => console.warn('final',results))

explanation

  1- initalize the result array from the given users
  [ 
   { userId: X, projcts: [] }, 
   { userId: Y, projcts: [] }, 
    ....
  ]

  2- for each give users we want the projects ids he/she has
  so the first switchMap will return (in order)
  [
   [ 1, 2, 3, ...] project ids for the first user,
   [ 8, 12, 63, ...] project ids for the second user,
   ...
  ]

  3- in the second switchMap we iterate over the previous array
  (which is an array that each item in it is an array of projects ids)

  so we needed two forkJoin the outer will iterate over each array of projects ids(the big outer 
  array previously mentioned)
  the inner one will iterate over each single project id and resolve it's observable value(which is the
  project details)

  4- finally in the tap process we have an array of array like the 2nd step but this time each
  array has the projects details and not the projects ids

  [
   { userId:1, projects: [ { id:1, details: 'details about 1' }, { id:2, details: 'details about 2' }]},
   { userId:2, projects: [ { id:2, details: 'details about 2' }, { id:4, details: 'details about 4' }]},
   { userId:3, projects: [ { id:3, details: 'details about 3' }, { id:6, details: 'details about 6' }]}
  ]

Upvotes: 1

Related Questions