在另一个Observable的数组项中映射一个Observable,将结果展平

时间:2020-06-12 21:25:22

标签: typescript rxjs angularfire rxjs-observables

此标题可能需要更多说明。

基本上,我从后端得到的是一个带有赛车驱动程序数组的Observable,并且我想向每个数组项映射另一个属性isOnTrack,该属性包含从后端检索的另一个Observable(简单布尔值)。我想展平最终结果,所以我在Observable中没有Observable。我已经尝试过许多rxjs运算符,但无法使其正常工作。

无效的代码:

this.drivers$ = this.db.list('users').valueChanges().pipe(
  map(arr => arr.map( (driver:any) => {
    driver.isOnTrack = this.db.object(`telemetry/${driver.uid}/values/IsOnTrack`).valueChanges();
     return driver
  })),
  mergeAll()
);

这成功地将isOnTrack可观察到的映射到数组项,但我无法将其展平。

项目在RxJS 6上

更新1

在乔纳森(Jonathan)回答之后,我相信我应该使用unpacked这个词而不是弄平

我要寻找的转换后的Observable应该提供类似于

的内容
of([
  {id: 1, name: 'foo', isOnTrack: true},
  {id: 2, name: 'bar', isOnTrack: true},
  {id: 3, name: 'baz', isOnTrack: false},
])

在后端更改一个IsOnTrack之后,它应该再次发出完整的数组。

of([
  {id: 1, name: 'foo', isOnTrack: false},
  {id: 2, name: 'bar', isOnTrack: true},
  {id: 3, name: 'baz', isOnTrack: false},
])

1 个答案:

答案 0 :(得分:1)

模拟数据库功能

// this.db.list('users').valueChanges()
const requestIsOnTrack$ = (id: number): Observable<boolean> => interval(1000).pipe(
  take(3),
  map(() => Math.random() >= 0.5)
)

// this.db.object(`telemetry/${driver.uid}/values/IsOnTrack`).valueChanges()
const requestDrivers$ = () => of([
  {id: 1, name: 'foo'},
  {id: 2, name: 'bar'},
  {id: 3, name: 'baz'},
])

实施

const drivers$ = requestDrivers$().pipe(
  map(drivers => drivers.map(driver => requestIsOnTrack$(driver.id).pipe(
    take(1),
    map(isOnTrack => ({
      ...driver,
      isOnTrack
    }))
  ))),
  mergeAll(),
  combineAll()
)

说明

可观察对象中的对象类型仅为<T>,以便不使用接口。

  • 从数据库中请求所有驱动程序:requestDrivers$() => Observable
  • 将请求isOnTrack映射到每个驱动程序requestIsOnTrack$(id) => Observable<Observable<T>[]>
  • 使用requestOnTrack将您的take(1) => Observable<Observable<T>[]>更新限制为1
  • 将先前的值映射到新对象({...driver, isOnTrack}) => Observable<Observable<T>[]>
  • mergeAll将您的数组分成多个发射mergeAll() => Observable<Observable<T>>
  • combineAll取消对可观察对象的装箱并将所有映射的值绑定到数组combineAll() => Observable<T[]>

这是正在运行的stackblitz