【问题标题】:Mapping an Observable in array items of another Observable, flattening the result在另一个 Observable 的数组项中映射一个 Observable,将结果展平
【发布时间】:2020-10-02 18:30:02
【问题描述】:

这个标题可能需要更多解释。

基本上我从后端得到的是一个带有一组赛车手的 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

在乔纳森的回答之后,我相信我应该使用 unpacked 这个词而不是 flattening

我要寻找的转换后的 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},
])

【问题讨论】:

    标签: typescript rxjs angularfire rxjs-observables


    【解决方案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()
    )
    

    说明

    在 observables 中的对象类型只是 &lt;T&gt; 以便于不使用接口

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

    这是一个正在运行的stackblitz

    【讨论】:

    • 您好乔纳森,非常感谢您的回答和投入的时间。尽管您的答案可能正是我所要求的,但由于我的措辞不佳,最终的 observable 并不是我真正想要的。最终的 observable 应该仍然是一个驱动程序数组,只是其中包含解包的 IsOnTrack Observable。
    • @PetertenKlooster 没问题。可能发生在开发阶段。我更新了我的答案,所以你得到了一个数组。要记住两件事。 1. 我使用了 take(1),这样 requestIsOnTrack$ 就不会一直更新结果。如果您不想要,请更改此设置。 2. 通过 combineAll 的使用,您需要等到每个 isOnTrack 至少发出一个值(针对每个驱动程序),然后才能发出最终结果。
    • 嗨乔纳森,这很好用!多谢。我可以立即访问所有值,所以这不是问题。
    • 很高兴能帮上忙 :)
    猜你喜欢
    • 2018-11-21
    • 2021-12-28
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多