在不完整的 RxJS 流中展平嵌套数据结构

Flatten nested data-structure in a non-complete RxJS stream

我想展平从商店获得的值,并在商店发出时将它们作为单个数组发出。

在下面我的 No-RxJS 示例中的同步版本中非常容易,但我无法弄清楚如何使用 RxJS 做到这一点。

我假设我可以使用 RxJS 来缓冲来自单个 .next 调用的值。

我应该为此使用 RxJS 运算符吗?如果是,那么如何将嵌套数据结构扁平化?

这是我要实现的目标的最小示例。

const store$ = new Rx.BehaviorSubject([])

store$.next([
  {
    id: 1,
    items: [
      {
        id: 1,
        title: 'Foo'
      },
      {
        id: 2,
        title: 'Bar'
      }
    ]
  },
  {
    id: 2,
    items: [
      {
        id: 3,
        title: 'Fizz'
      },
      {
        id: 4,
        title: 'Buzz'
      }
    ]
  },
]);

// Desired output: [ "Foo", "Bar", "Fizz", "Buzz" ]

store$
  .filter(({length}) => length > 0)
  .flatMap(group => group)
  .flatMap(({items}) => items)
  .map(({title}) => title)
  .subscribe(console.log) // Emits separate values :-(

// No-RxJs approach

store$
  .filter(({length}) => length > 0)
  .map(groups => groups
        .map(
          ({ items }) => items.map(
            ({ title }) => title
          )
        )
        .reduce((next, acc) => [ ...acc, ...next ], []))
  .subscribe(console.log) // Works as expected.
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.js"></script>

正如 @zeroflagl in comments, toArray 所建议的那样,方法非常有效。

因为它只适用于已完成的可观察对象,所以我不得不 swithchMap 到一个可观察对象,它使用 take(1) 来获得具有当前存储值的已完成可观察对象。

store$
    .filter(({ length }) => length > 0)
    .switchMap(() => store$.take(1)
        .flatMap(group => group)
        .flatMap(({ items }) => items)
        .map(({ title }) => title)
        .toArray()
    )
    .subscribe(console.log) // Emits flat array