rxjs:从2个端点加载多对多,并合并到单个可观察对象中

rxjs:从2个端点加载多对多,并合并到单个可观察对象中,rxjs,rxjs6,rxjs-observables,rxjs-pipeable-operators,Rxjs,Rxjs6,Rxjs Observables,Rxjs Pipeable Operators,我有一个端点用于获取用户列表,另一个端点用于获取每个用户的公寓列表: getUsers() => Observable<User[]>; getUserApartments(userId) => Observable<Apartment[]>` 如何将这两个数据合并为单个可观察数据: const usersWithApartments$: Observable<{ user: User, apartments: Apartment[] }[]>

我有一个端点用于获取用户列表,另一个端点用于获取每个用户的公寓列表:

getUsers() => Observable<User[]>;
getUserApartments(userId) => Observable<Apartment[]>`
如何将这两个数据合并为单个可观察数据:

const usersWithApartments$: Observable<{ user: User, apartments: Apartment[] }[]> = getUsers().pipe(
    // users.map(user => { user, apartments: getUserApartments(user.id) }) <-- turn this pseudocode into Rxjs
);
就是这样:

const toUserWithApartmentsStream = (user: User) => getUserApartments(user.id).pipe(
  map((apartments: Apartment[]) => ({ user, apartments }))
);

const usersWithApartments$: Observable<{ user: User, apartments: Apartment[] }[]> =
  getUsers().pipe(
    switchMap((users: User[]) => users),
    concatMap((user: User) => toUserWithApartmentsStream(user)),
    toArray()
  );
现在GetUserPlaments将一个接一个地连续执行,我可以编写mergeMap而不是concatMap,GetUserPlaments将并发执行。感谢拉菲·海尼格的评论

函数toUserWithApartmentsStream只是一个助手,因此代码看起来更干净。我可以直接把它写在concatMap中。

就是这样:

const toUserWithApartmentsStream = (user: User) => getUserApartments(user.id).pipe(
  map((apartments: Apartment[]) => ({ user, apartments }))
);

const usersWithApartments$: Observable<{ user: User, apartments: Apartment[] }[]> =
  getUsers().pipe(
    switchMap((users: User[]) => users),
    concatMap((user: User) => toUserWithApartmentsStream(user)),
    toArray()
  );
现在GetUserPlaments将一个接一个地连续执行,我可以编写mergeMap而不是concatMap,GetUserPlaments将并发执行。感谢拉菲·海尼格的评论

函数toUserWithApartmentsStream只是一个助手,因此代码看起来更干净。我可以直接在concatMap中内联编写它。

因为getUsers的返回类型是Users[],所以我假设所需的类型是{user:user,partments:partments[]>的集合,而不是一个集合

请考虑下面的实现:

阶级公寓{ 用户:用户; 公寓:公寓[]; } const usersWithApartments$:Observable=getUsers 管 switchMapusers=>forkJoin users.mapuser=>getUserApartmentsuser.id.pipe 地图公寓=>{用户,公寓} ; 因为getUsers的返回类型是Users[],所以我假设所需的类型是{user:user,plants:plant[]>的集合,而不是单个集合

请考虑下面的实现:

阶级公寓{ 用户:用户; 公寓:公寓[]; } const usersWithApartments$:Observable=getUsers 管 switchMapusers=>forkJoin users.mapuser=>getUserApartmentsuser.id.pipe 地图公寓=>{用户,公寓} ;
您的解决方案缺少可用性concurrency@RafiHenig如果作者不想同时向api发送大量请求,该怎么办?我不会说这个答案缺乏并发性,我会说这个特定的答案将连续执行请求,以避免同时发送太多请求并使事情变得更糟或者,我可以编写mergeMap而不是switchMap,我的答案将具有并发性。@Goga Koreli通常需要并发性,此外,mergeMap不保证合并的可观察对象将以与源Arrive中的项相同的顺序发出api响应。我同意,通常是这样。在该sp的真实场景中具体的例子是,如果有很多用户,这将导致同时发送大量网络呼叫,如果有多个经过身份验证的用户同时这样做,这将更加严重。因此,对后端的影响很大。顺便说一句,我同意mergeMap不能保证到达的顺序,但当结果为在这两种情况下都使用数组。您的解决方案缺少concurrency@RafiHenig如果作者不想同时向api发送大量请求,该怎么办?我不会说这个答案缺乏并发性,我会说这个特定的答案将连续执行请求,以避免同时发送太多的请求更糟糕的是,作为替代,我可以编写mergeMap而不是switchMap,我的答案将具有并发性。@Goga Koreli通常需要并发性,此外,mergeMap不保证合并的可观察对象将以与源中的项相同的顺序发出api响应。我同意,通常是这样。在现实世界中对于这个特定示例的场景,如果有很多用户,这将导致同时发送大量网络呼叫,如果有多个经过身份验证的用户同时这样做,则情况会更糟。因此对后端造成严重影响。顺便说一句,我同意mergeMap不保证到达顺序,但我不认为有理由提及它当两种情况下的结果都是数组时。正确!在问题中修复了它。感谢您的解决方案!正确!在问题中修复了它。感谢您的解决方案!