简体   繁体   English

如何将多个 rxjs observables 与单个订阅结合起来?

[英]How to combine multiple rxjs observables with a single subscription?

I have an observable to get users , and I then want to do a API calls to get roles for each user, and then combine all the data into a single array of objects for display.我有一个 observable 来获取users ,然后我想调用 API 来获取每个用户的roles ,然后将所有数据组合到一个对象数组中进行显示。

I have gotten to this point, but I think there must be a way for me to combine the roles calls with the users in stream rather than having to subscribe and then combineLatest:我已经到了这一点,但我认为必须有一种方法可以将角色调用与 stream 中的用户结合起来,而不是必须先订阅然后再组合最新:

  this.getAllUsersParams$
    .pipe(
      switchMap(params => this.userFacadeService.sysadminGetAllUsers(params)),
      map(allUsers => {
        const rolesCalls: Observable<UserRoles[]>[] = [];

        allUsers.users.forEach(user => {
          rolesCalls.push(this.userFacadeService.getUserRoles(user.id));
        });

        return { allUsers, rolesCalls };
      })
    )
    .subscribe(data => {
      combineLatest(data.rolesCalls)
        .pipe(
          map(userRoles => {
            const userListVM: UserListVM[] = data.allUsers.users.map((user, i) => {
              return {
                ...user,
                roles: userRoles[i],
              };
            });
            return { userListVM, total: data.allUsers.total };
          })
        )
        .subscribe(data => {
          // consume data
        });
    })

Are you looking for something like this?你在寻找这样的东西吗?

this.getAllUsersParams$
  .pipe(
    switchMap(params => this.userFacadeService.sysadminGetAllUsers(params)),
    switchMap(allUsers => combineLatest(
      allUsers.users.map(user => combineLatest([
        of(user),
        this.userFacadeService.getUserRoles(user.id),      
      ])
    )),
    map((result): { total: number, userListVM: UserListVM[] } => ({
      total: result.length,
      userListVM: result.map(user => ({
        ...user[0],
        roles: user[1]
      }))
    }))
  )
  .subscribe(data => {
    ...
  });

It pairs each user with their roles, then you can manipulate the data to be the structure you want.它将每个用户与其角色配对,然后您可以将数据操作为您想要的结构。

If you do the mapping right when you retrieve the user's role, you can skip the need for looking up values later.如果您在检索用户角色时正确执行映射,则可以跳过稍后查找值的需要。 The following maps the array of users to an observable that emits a single UserListVM object.下面将用户数组映射到发出单个 UserListVM object 的 observable。 From there the forkJoin executes each observable and returns an array of results.从那里forkJoin执行每个 observable 并返回一个结果数组。 Finally map adds the total property to the emitted object.最后map将总属性添加到发出的 object 中。

this.getAllUsersParams$.pipe(
  switchMap(params => this.userFacadeService.sysadminGetAllUsers(params)),
  switchMap(allUsers => 
    forkJoin(allUsers.users.map(user => 
      this.userFacadeService.getUserRoles(user.id).pipe(
        map(roles => ({ user, roles } as UserListVM) )
      )
    ))
  ),
  map(userListVM => ({ userListVM, total: userListVM.length })) // userListVm: UserListVM[]
)

You might consider using concat and toArray instead of forkJoin as it will execute all observables simultaneously.您可能会考虑使用concattoArray而不是forkJoin ,因为它将同时执行所有 observables。 The following will execute each role request one by one and then when the last executes convert the emissions into a single array.以下将逐个执行每个角色请求,然后在最后一次执行时将排放转换为单个数组。

this.getAllUsersParams$.pipe(
  switchMap(params => this.userFacadeService.sysadminGetAllUsers(params)),
  switchMap(allUsers => 
    concat(...allUsers.users.map(user => 
      this.userFacadeService.getUserRoles(user.id).pipe(
        map(roles => ({ user, roles } as UserListVM))
      )
    ))
  ),
  toArray(),
  map(userListVM => ({ userListVM, total: userListVM.length }))
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM