Sitemap
Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.

Angular: Grouping Data Based on Single and Multiple Keys Using RxJS

--

The groupBy RXJS operator can be easily used to group data based on single key. We shall see in this story that it can be used to group based on multiple keys as well with the help of pipes.

We shall be using a pipe to reuse the logic to group the data based on single and multiple keys.

GroupPipe: The transform() accepts 2 arguments here. The first argument is the array of objects to be grouped and the 2nd argument is the key based on which the grouping needs to be performed. I have added a tap operator after every other operator to check what each operator does.

@Pipe({name: ‘group’})

export class GroupPipe implements PipeTransform {
transform(arr: any, key: string): any {
console.log(‘executing for key:’, key);

return from(arr).pipe(
groupBy((elem: any) => elem[key]),
tap((response: any) => console.log(response)),
mergeMap((group) => group.pipe(toArray())),
tap((response: any) => console.log(response)),
toArray(),
tap((response: any) => console.log(response))
);
}
}

I. Single-Key Grouping

For the single-key grouping, we shall be grouping the below set of numbers into even and odd types. The type property of each object will be the key.

numbers = [
{ type: ‘odd’, value: 1 },
{ type: ‘odd’, value: 3 },
{ type: ‘even’, value: 2 },
{ type: ‘odd’, value: 5 },
{ type: ‘even’, value: 6 },
{ type: ‘odd’, value: 7 },
{ type: ‘even’, value: 8 },
{ type: ‘odd’, value: 9 },
{ type: ‘even’, value: 10 },
{ type: ‘odd’, value: 11 },
{ type: ‘even’, value: 12 },
];

Below is the template:

<h3>Simple Grouping based on single key</h3>

<div class=”group” *ngFor=”let innerArr of numbers | group: ‘type’ | async”>
<b>Key:{{ innerArr[0].type }}</b>

<div *ngFor=”let num of innerArr”>
<label>{{ num.value }} </label>
</div>
</div>

We are iterating through the array property numbers. This array is passed as the first argument to the group pipe and the string “type” is passed as the 2nd argument to the pipe. “type” is the key based on which we will be grouping the data into even and odd number sets.

The group pipe is expected to return an observable ,which will be subscribed to, using the async pipe.

The observable will emit an array, which in turn will contain 2 sub-arrays. One sub-array will contain only the odd numbers and the other sub-array will contain the even numbers.

Below is how the main array and 2 sub-arrays look like. We shall see shortly how we got to this array via the GroupPipe.

Press enter or click to view image in full size

The innerArr in the below code, refers to each sub-array in the main array which the observable emits. num refers to each object in the sub-array: innerArr.

<div class=”group” *ngFor=”let innerArr of numbers | group: ‘type’ | async”>
<b>Key:{{ innerArr[0].type }}</b>

<div *ngFor="let num of innerArr">
<label>{{ num.value }} </label>
</div>
</div>

Now lets see how the GroupPipe has functioned.

  1. The first tap operator below logs the output of the groupBy operator. The from operator creates an observable which emits objects from the array of objects: arr. The groupBy operator groups the objects emitted by the observable based on the key we provide. In this example, the key is obtained from the type property in each object of the array. The operator then emits these grouped items as GroupedObservables. Since the key: type property can contain only 2 values: odd and even, we have 2 GroupedObservables.
return from(arr).pipe(
groupBy((elem: any) => elem[key]),
tap((response: any) => console.log(response)),
....
);

The groupBy operator emits 2 GroupedObservables for the 2 key properties: odd and even, as you can see below. We expect that the GroupedObservable with key property “odd” will emit all objects which have the type property as “odd” and the GroupedObservable with key property “even” will emit all objects which have the type property as “even”.

Press enter or click to view image in full size

Moving to the next tap operator below. Each of the GroupedObservable emitted by the groupBy operator is passed to the mergeMap operator. Each object emitted by the outer GroupedObservable is mapped to an inner observable returned by the toArray() operator.

mergeMap((group) => group.pipe(toArray())),
tap((response: any) => console.log(response)),

The inner observable returned by the toArray() emits an array of the objects(i.e objects emitted by the outer GroupedObservable) as you can see below.

Press enter or click to view image in full size

All these inner observables are merged into a single output observable by the mergeMap operator.

Get Angular&NodeEnthusiast’s stories in your inbox

Join Medium for free to get updates from this writer.

Moving to the next tap operator below, which logs the output of the toArray() operator. The toArray() operator here combines the values emitted by the output observable(returned by the mergeMap operator) into another array.

toArray(),
tap((response: any) => console.log(response))

The observable returned by the toArray() operator will return this array which in turn consists of 2 sub-arrays. This is the output we have already seen previously.

Press enter or click to view image in full size

The observable returned by the toArray() is the observable returned by the GroupPipe, to which we are subscribing using the async pipe in the template.

II. Multi-Key Grouping

I have used a dummy JSON based on olympic athletes, the country they hail from and the year they won medals. Below is a sample object from this JSON.

{“athlete”:”Michael Phelps”,”age”:23,”country”:”United States”,”year”:2008,”date”:”24/08/2008",”sport”:”Swimming”,”gold”:8,”silver”:0,”bronze”:0,”total”:8}

We shall be grouping the data first based on the key: country property and then for each country we shall perform the grouping based on the key:year property in each object.

Below is the template. This is something very similar to what we have done for Single-Key Grouping. The only difference is the additional grouping we perform again for the key: year property.

<h3>Grouping based on multiple keys</h3>

<div class=”group” *ngFor=”let innerArr of olympics | group: ‘country’ | async”>

<b>Key: {{ innerArr[0].country }}</b>

<p>Total No of athletes in <b>{{ innerArr[0].country }}</b>:
<b>{{ innerArr.length }}</b></p>

<h4>Grouping each country based on year</h4>

<div *ngFor=”let item of innerArr | group: ‘year’ | async”>
<b>Key: {{ item[0].year }}</b>
<p>No of athletes in <b>{{ item[0].country }}</b> in <b>{{ item[0].year }}</b>
:<b>{{ item.length }}</b>
</p>

</div>
</div>

You can find the entire working example below.

Stackademic

Thank you for reading until the end. Before you go:

  • Please consider clapping and following the writer! 👏
  • Follow us on Twitter(X), LinkedIn, and YouTube.
  • Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.

--

--

Angular&NodeEnthusiast
Angular&NodeEnthusiast

Written by Angular&NodeEnthusiast

Loves Angular and Node. I wish to target issues that front end developers struggle with the most.

Stackademic
Stackademic

Published in Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.