RXJS groupBy Observable <Object[]>

rxjs groupby array of objects
rxjs groupby multiple properties
rxjs groupby mergemap
observable groupby java
angular 7 group by array
rxjs sort
angular 6 group by array
typescript group by

I have entries$: Observable<BooksOverviewGroup[]>;:

and i would like to group them by groupId. I tried like this:

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

However, it didn't work. How can I group by groupId in this case ? (Observable<Object[]>)

Higher-Order Observable

If you want a higher-order observable, you can actually use the groupBy rxjs operator.

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);

This will result in an observable which emits one observable per group, and on each of those inner observables, the corresponding items will be emitted.

Observable of Groups

If instead you want an observable which simply emits the groups, then this has actually nothing to do with rxjs or its groupBy operator. Instead, it's merely a basic question about how to group an array in Javascript.

There is no built-in method for this, but libraries like lodash come with such functions. You can also do it by hand:

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);

This will emit once for the entire data set, but will emit

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

groupBy, groupBy marble diagram. When the Observable emits an item, a key is computed for this item with the keySelector function. If a GroupedObservable for this key  An Observable representing values belonging to the same group represented by a common key. The values emitted by a GroupedObservable come from the source Observable. The common key is available as the field key on a GroupedObservable instance.

You almost got it.

Try using mergeMap() or concatMap() before groupBy().

So an example:

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);

Output:

(2) [25, Array(2)]
(2) [30, Array(1)]
(2) [35, Array(1)]

groupBy, The groupBy operator would create individual Observable streams for each key within the source data. Each of these Observable streams would  RxJS - Javascript library for functional reactive programming. Rx.Observable.prototype.groupBy(keySelector, [elementSelector], [comparer]) Groups the elements of an observable sequence according to a specified key selector function and comparer and selects the resulting elements by using a specified function.

Just use the groupBy operator, then merge them all.

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

Here is what I've learn about groupBy operator by reading RxJS , RxJS groupBy groupByUntil​​ (required) a function that accepts an item from the source Observable and returns its key. a function that accepts an item from the source Observable and returns an item to be emitted in its place by one of the resulting Observables. RxGroovy implements the groupBy operator. The Observable it returns emits items of a particular subclass of Observable — the GroupedObservable.

GroupBy operator, ( Observable ): A sequence of observable groups, each of which corresponds to a unique key value, containing all elements that share that same key value. Rx.Observable.prototype.groupBy(keySelector, [elementSelector]) Groups the elements of an observable sequence according to a specified key selector function and comparer and selects the resulting elements by using a specified function.

groupBy, As a cyclist is moving, I want to know how often they are moving at that specific velocity (speed). Our weapon of choice is the RxJS groupBy()  The groupBy operator would create individual Observable streams for each key within the source data. Each of these Observable streams would then have the individual data elements that belonged to

Partitioning RxJS streams: adventures in nested Observables with , In groupBy operator, the output is grouped based on a specific condition and these group items are emitted as GroupedObservable. * A function that returns an Observable to determine how long each group should * exist. * @return {Observable<GroupedObservable<K,R>>} An Observable that emits * GroupedObservables, each of which corresponds to a unique key value and each * of which emits those items from the source Observable that share that key * value. * @name groupBy */

Comments
  • Do you actually want to group it into a higher order observable? Or do you actually mean to convert it into an observable of a list of groups?
  • I would like to group this by GroupID and get them as array back. Now i start with Observable<Object[]> (cause of the [] groupby didnt get me) Maybe I just need to turn this Observable<Object[]> to something like normal array and use the normal groupby. Do you know how to turn it to normal array?
  • You didn't answer my question. Do you want a higher order observable (an observable emitting one observable per group) or a single observable that emits groups?
  • Sorry for that, I would like to see both variants to learn how to process the data. If it's too costly, I would like to see the solution for the higher order observable. Thank you.
  • Did you find any solution? I am also confused why groupBy is giving me back an array so I can't group..
  • Thanks for your help and your time. However in case of the Higher-Order Observable: from(data).pipe( groupBy(item => item.groupId) ) I tried this before but it didn’t work because I have an array of Observable, ist not just plain object like Object ; It’s an Object[] groupId is unknow in item, because item in this case is an array of object [] But if i go further : groupBy(books => books.map(book => book.groupId)) it thinks i take array as key and turns out wrong. I will give observable of groups a try.
  • it doesn't work with Observable<object[]>. I got an Array as key back.
  • Rxjs 6.3.2 + Angular 6.1.8 -> what @dunaskdunsay says, you you get an array back. In the code example below, typescript gives the error 'property age does not exist on type '{ name: string; age: number; }[]' const people = [{ name: 'Sue', age: 25 }, { name: 'Joe', age: 30 }, { name: 'Frank', age: 25 }, { name: 'Sarah', age: 35 }]; const source = of(people); const example = source.pipe(groupBy(p => p.age)); example.subscribe(val => console.log(val));