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[]>)
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)]
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.
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}
]
}
Just use the groupBy
operator, then merge them all.
$data.pipe(
groupBy(book => book.groupId),
mergeMap(group => group.pipe(toArray()))
)
.subscribe(console.log)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With