Jacek
Jacek

Reputation: 12063

How to use grouping key in GroupBy in RxJS,

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

Upvotes: 3

Views: 3124

Answers (3)

Adrian Brand
Adrian Brand

Reputation: 21658

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 => {});

Upvotes: 1

Poul Kruijt
Poul Kruijt

Reputation: 71971

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

Upvotes: 2

micronyks
micronyks

Reputation: 55453

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

Upvotes: 1

Related Questions