I have a very large array of items where there is a "Status" field that could have one of six statuses. Using the rxjs library, I am trying to .groupBy then .reduce to return an array of the six statuses and the count of items with those statuses.
Here is the method in my service:
getStatusTotals() {
return Observable.from(sampleData)
.map(res => res.d.results)
.concatMap(data => data)
.groupBy(item => item.Status)
.mergeMap(group => group
.reduce((total, item) => total, 0)
.map(total => ({ Status: group.key, Count: total }))
)
.toArray()
}
In the component where I am calling this service function, I set the value to statusData and the information is being presented as follows:
<div *ngFor="let t of tracdata | async" class="row">Status: {{t.Status}}; Count: {{t.Count}}</div>
This, however is giving me the following in my app:
Status: 5 - Dormant; Count: 0
Status: 2 - Active; Count: 0
Status: 4 - Assigned to Section; Count: 0
Status: 1 - Pending Review; Count: 0
Status: 3 - Officer Review; Count: 0
So I am doing something wrong. I have tried .count and .forEach, and read through the rxjs documentation, but I must be doing something wrong. Please help!
Your reduce is missing +1 for actually counting the statuses
.reduce((total, item) => total + 1, 0)
Anyway, you can replace the .reduce(..) with .count()
As @ZahiC said, reduce will work.
But reduce will only emit once you've got all the data.
If you want to compute all of that every time there's a next, you should use scan instead.
Here's an example :
const { Observable } = Rx;
const sampleData = [
{ status: 'status1' },
{ status: 'status2' },
{ status: 'status1' },
{ status: 'status3' },
{ status: 'status4' },
{ status: 'status2' },
{ status: 'status5' },
{ status: 'status6' },
{ status: 'status4' }
];
Observable
.from(sampleData)
.scan((acc, curr) => {
const status = curr.status;
const count = acc[status] ? acc[status].count : 0;
return Object.assign(acc, {
[status]: { status, count: count + 1 }
});
}, {})
.do(console.log)
.subscribe();
And a working Plunkr: https://plnkr.co/edit/U2mZC5QpL12NpuHTJOFq?p=preview
EDIT:
As this function gives an object and you want an array, I've added a small function for that :
const objToArray = (obj) => {
const keys = Object.keys(obj);
return keys.reduce((acc, curr) => [...acc, obj[curr]], []);
}
Then I just map the Observable to it before the do :
...
.map(objToArray)
.do(console.log)
.subscribe();
The output is the following :
(notice that we have the intermediate results !)
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