How to use grouping key in GroupBy in RxJS,

Viewed 1586

I have structure returned by API

This is signature

methodApi(): Observable(Array<MyClass>)

This is data

{ id: 1, name: 'Red', parentId: null }
{ id: 2, name: 'Apple', parentId: 1 }
others

I want to group it by parentId

methodApi()
.pipe(groupby((x: MyClass[] => ...))) // THERE
.subscribe(x => console.log(x));

MethodApi return Observable<Array>, in 'groupby' method as input parameter I have array, so I cannot refer to parentId property. When I change input param to MyClass then I get a compilation error.

How to resolve this grouping? I use Angular 9.0 with RxJS 6.5.5

3 Answers

You will have to create another observable stream from your array by using from, and then use the groupBy and after that convert it back to a result array:

methodApi().pipe(
  concatMap((result) => from(result)),
  groupBy((item) => item.parentId),
  mergeMap(group => group.pipe(toArray()))
).subscribe(x => console.log(x));

example stack

You can also use mergeAll:

methodApi().pipe(
  mergeAll(),
  groupBy((item) => item.parentId),
  mergeMap(group => group.pipe(toArray()))
).subscribe(x => console.log(x));

example stack

It should be simple using groupBy operator as below,

methodApi().pipe(
  groupBy((item) => item.parentId),
  mergeMap(group => group.pipe(toArray()))
).subscribe(console.log) // should get you an array with groupBy parentId

This is not how the RxJs group by operator works. The RxJs operator groups objects that get emitted by the stream, you are looking to group items in an array that is emitted by the stream. You need a group by function that works on arrays, not observables. You could use a simple reduce that groups them all to an object with the parentId as the key.

methodApi()
.pipe(map(results => results.reduce(
  (group, item) => {
    if (group[item.parentId]) {
      group[item.parentId].push(item);
    } else {
      group[item.parentId] = [item];
    }
    return group;
  }, {})
)).subscribe(group => {});
Related