RXJS groupBy Observable - PullRequest
       8

RXJS groupBy Observable

0 голосов
/ 14 мая 2018

у меня entries$: Observable<BooksOverviewGroup[]>;:

enter image description here

и я хотел бы сгруппировать их по groupId. Я пытался так:

groupBy(books => books.map(book => book.groupId)),
 mergeMap(innerObs => innerObs.skip(1).map(books => books.map(book => book.groupTitle)));

Однако это не сработало. Как я могу сгруппировать по groupId в этом случае? (Observable<Object[]>)

Ответы [ 3 ]

0 голосов
/ 15 мая 2018

Наблюдаемый более высокого порядка

Если вы хотите наблюдаемый более высокого порядка, вы можете использовать оператор groupBy rxjs.

const data = [
  {groupId: "foo", value: 1},
  {groupId: "foo", value: 3},
  {groupId: "foo", value: 5},
  {groupId: "bar", value: 42},
  {groupId: "bar", value: 1337},
];

from(data).pipe(
  groupBy(item => item.groupId)
)
  .subscribe(console.log);

Это приведет к тому, что наблюдаемое излучаетпо одной наблюдаемой на группу, и на каждой из этих внутренних наблюдаемых будут выбрасываться соответствующие элементы.

Наблюдаемые группы

Если вместо этого вам нужна наблюдаемая, которая просто излучает группы, то это имеетна самом деле ничего общего с rxjs или его оператором groupBy.Вместо этого это просто основной вопрос о том, как сгруппировать массив в Javascript.

Для этого нет встроенного метода, но библиотеки, такие как lodash, поставляются с такими функциями.Вы также можете сделать это вручную:

const data = [
  {groupId: "foo", value: 1},
  {groupId: "foo", value: 3},
  {groupId: "foo", value: 5},
  {groupId: "bar", value: 42},
  {groupId: "bar", value: 1337},
];

const groupBy = (data, keyFn) => data.reduce((agg, item) => {
  const group = keyFn(item);
  agg[group] = [...(agg[group] || []), item];
  return agg;
}, {});

of(data).pipe(
  map(data => groupBy(data, item => item.groupId)
)
  .subscribe(console.log);

Это будет излучать один раз для всего набора данных, но будет генерировать

{
  "foo":[
    {"groupId":"foo","value":1},
    {"groupId":"foo","value":3},
    {"groupId":"foo","value":5}
  ],
  "bar":[
    {"groupId":"bar","value":42},
    {"groupId":"bar","value":1337}
  ]
}
0 голосов
/ 25 мая 2019

Вы почти получили это.

Попробуйте использовать mergeMap() или concatMap() до groupBy().

Так пример:

const people = [
  { name: 'Sue', age: 25 },
  { name: 'Joe', age: 30 },
  { name: 'Frank', age: 25 },
  { name: 'Sarah', age: 35 }
];

of(people) // <- this gets Observable<Object[]>
  .pipe(
    mergeMap(res => res), // <- use concatMap() if you care about the order
    groupBy(person => person.age, p => p.name),
    mergeMap(group => zip(of(group.key), group.pipe(toArray())))
  )
  .subscribe(console.log);

Вывод:

(2) [25, Array(2)]
(2) [30, Array(1)]
(2) [35, Array(1)]
0 голосов
/ 15 мая 2018

Просто используйте оператор groupBy , затем объедините их все.

$data.pipe(
    groupBy(book => book.groupId),
    mergeMap(group => group.pipe(toArray()))
)
.subscribe(console.log)
...