I want to group the user by type(contractor or staff) and sum the Unit(words / hrs) and Cost.
I have tried the following code but no luck.
this.jobsGroupBy = of(this.jobDetails).pipe(
groupBy((val:any) => val.userId && val.cont),
mergeMap((val$:any) =>
val$.pipe(
reduce((acc:any, curr:any) => {
acc.tCost = Number(acc.tCost) + Number(curr.tCost);
this.jobsGroupBy = acc;
return acc;
})
)
)
);
console.log('result :'+ JSON.stringify(this.jobsGroupBy));
The output is: result :{"source":{}}
In my opinion you do not really need rxjs for these scenarios, you can solve this with simple js reduce
, But if rxjs is essential please check the next block of rxjs code.
const reduced = jobDetails.reduce((acc: any, val: any) => {
const key = `${val.userId}-${val.cont}-${val.unit}`;
if(!acc[key]) {
acc[key] = val;
} else {
acc[key]['amount'] += val['amount'];
acc[key]['tCost'] += val['tCost'];
}
return acc;
}, {});
console.log('result :' + JSON.stringify(Object.values(reduced)));
We need to use from
to convert the array, into a stream of observables.
Then we use groupBy
to group based on a key ${val.userId}-${val.cont}-${val.unit}
I am grouping by userId
, cont
and unit
.
After grouping, we will get distinct arrays of rows matching the groups, which we can use reduce
to sum up the number fields and finally return the result one by one.
Optionally you can use toArray
to sum up all the results and return it one one go.
from(jobDetails)
.pipe(
groupBy((val: any) => `${val.userId}-${val.cont}-${val.unit}`),
mergeMap((group: any) =>
group.pipe(
reduce((acc: any, curr: any) => {
if (!acc) {
acc = curr;
} else {
acc['amount'] += curr['amount'];
acc['tCost'] += curr['tCost'];
}
return acc;
}, null)
)
)
// toArray(), // <- returns only once when enabled
)
.subscribe((jobsGroupBy: any) => {
console.log('result :' + JSON.stringify(jobsGroupBy));
});
import { groupBy, mergeMap, reduce, toArray } from 'rxjs/operators';
import './style.css';
import { rx, of, map, from, zip } from 'rxjs';
// Open the console in the bottom right to see results.
const jobDetails = [
{ userId: 'test1', cont: 'staff', unit: 'Hours', amount: 0.5, tCost: 15 },
{ userId: 'test1', cont: 'staff', unit: 'Words', amount: 1500, tCost: 15 },
{ userId: 'test1', cont: 'staff', unit: 'Hours', amount: 1.5, tCost: 53 },
{ userId: 'test1', cont: 'staff', unit: 'Words', amount: 8576, tCost: 230 },
{ userId: 'test1', cont: 'contrator', unit: 'Hours', amount: 0.5, tCost: 15 },
{
userId: 'test1',
cont: 'contrator',
unit: 'Words',
amount: 1500,
tCost: 15,
},
{ userId: 'test1', cont: 'contrator', unit: 'Hours', amount: 1.5, tCost: 53 },
{
userId: 'test1',
cont: 'contrator',
unit: 'Words',
amount: 8576,
tCost: 230,
},
{ userId: 'test2', cont: 'staff', unit: 'Hours', amount: 0.5, tCost: 15 },
{ userId: 'test2', cont: 'staff', unit: 'Words', amount: 1500, tCost: 15 },
{ userId: 'test2', cont: 'staff', unit: 'Hours', amount: 1.5, tCost: 53 },
{ userId: 'test2', cont: 'staff', unit: 'Words', amount: 8576, tCost: 230 },
{ userId: 'test2', cont: 'contrator', unit: 'Hours', amount: 0.5, tCost: 15 },
{
userId: 'test2',
cont: 'contrator',
unit: 'Words',
amount: 1500,
tCost: 15,
},
{ userId: 'test2', cont: 'contrator', unit: 'Hours', amount: 1.5, tCost: 53 },
{
userId: 'test2',
cont: 'contrator',
unit: 'Words',
amount: 8576,
tCost: 230,
},
];
from(jobDetails)
.pipe(
groupBy((val: any) => `${val.userId}-${val.cont}-${val.unit}`),
mergeMap((group: any) =>
group.pipe(
reduce((acc: any, curr: any) => {
if (!acc) {
acc = curr;
} else {
acc['amount'] += curr['amount'];
acc['tCost'] += curr['tCost'];
}
return acc;
}, null)
)
)
// toArray(), // <- returns only once when enabled
)
.subscribe((jobsGroupBy: any) => {
console.log('result :' + JSON.stringify(jobsGroupBy));
});