The response from my http call is an array of company objects like this:
response = [{
"name": "CompanyName1",
"registrations": [
{
"country": "en",
"register": "registerType1",
"amount": 2
},
{
"country": "wa",
"register": "registerType2",
"amount": 1
},{
"country": "en",
"register": "registerType1",
"amount": 3
},
{
"country": "sc",
"register": "registerType3",
"amount": 2
},
{
"country": "wa",
"register": "registerType3",
"amount": 2
}
]
},
{
"name": "CompanyName2",
"registrations": [
{
"country": "wa",
"register": "registerType1",
"amount": 3
},
{
"country": "sc",
"register": "registerType3",
"amount": 1
}
]]
I need to group/sum company's registrations by register and country into a new propertyName (registerType_12) if registerType1 || registerType2 otherwise just keep property name registerTypeN. that is for companyName1 I need to get a result like this:
CompanyName1: [{country:en, registerType_12, amount:5},
{country:wa, registerTyoe_12, amount:1,
{country:sc, registerType3, amount:4}
}]
You don't need typescript or rxjs for this. It can be achieved with pure javascript.
JSBin link : https://jsbin.com/yujocofesu/edit?js,console
response.reduce((finalObj, obj)=>{
finalObj[obj.name] =
obj.registrations
.map(reg => Object.assign(reg,
{register: (
reg.register ==='registerType1'||
reg.register==='registerType2') ?
'registerType_12': reg.register
})
)
.reduce(mergeSimilar, []);
return finalObj;
},{});
function mergeSimilar(newList, item){
let idx = newList.findIndex(
i=> i.country === item.country && i.register === item.register);
if(idx>-1){
newList[idx].amount += item.amount;
}else{
newList.push(item)
}
return newList;
}
This gives response as
{
CompanyName1: [{
amount: 5,
country: "en",
register: "registerType_12"
}, {
amount: 1,
country: "wa",
register: "registerType_12"
}, {
amount: 2,
country: "sc",
register: "registerType3"
}, {
amount: 2,
country: "wa",
register: "registerType3"
}],
CompanyName2: [{
amount: 3,
country: "wa",
register: "registerType_12"
}, {
amount: 1,
country: "sc",
register: "registerType3"
}]
}
I made a Plunkr to demo how to do that: https://plnkr.co/edit/uO48fEVJGy2nwm587PO8?p=preview
Here's an explanation
I saved your data in a variable:
const { Observable } = Rx;
// FAKE DATA FROM BACKEND
const data = [
{
"name": "CompanyName1",
"registrations": [
{
"country": "en",
"register": "registerType1",
"amount": 2
},
...
]
},
{
"name": "CompanyName2",
"registrations": [
{
"country": "wa",
"register": "registerType1",
"amount": 3
},
...
]
}];
I made a mock for a Response
and Http.get
method so in the end we have something that really looks like Angular
code:
(These are not directly relevant for your problem)
// MOCK RESPONSE OBJECT
const response = () => {
const r = {
body: null
};
r.json = () => JSON.parse(r.body);
return r;
};
// MOCK HTTP METHOD
const http = {
get: (url) => {
const res = response();
res.body = JSON.stringify(data);
return Observable.of(res).delay(1000)
}
};
And here's how you could solve your problem in a clean way:
http
.get('some-url')
.map(res => res.json())
.map(groupByCompanyNameAndRegistration)
.do(data => console.log(data))
.subscribe();
Oubviously, the
groupByCompanyNameAndRegistration
is not made yet.
But we have a clean chain of
Observable
and it's really easy to understand what's going on.
The logic part of the code:
const flattenObj = (obj) =>
Object.keys(obj).map(key => obj[key]);
const groupByCompanyNameAndRegistration = (data) => {
return data.reduce((accComp, company) => {
if (!accComp[company.name]) {
accComp[company.name] = {};
}
const compObj = company.registrations.reduce((accReg, reg) => {
if (!accReg[reg.country]) {
accReg[reg.country] = {
country: reg.country,
amount: 0
};
}
accReg[reg.country].amount += reg.amount;
return accReg;
}, {});
accComp[company.name] = flattenObj(compObj);
return accComp;
}, {});
};
And finally, the console output :
{
"CompanyName1": [
{
"country": "en",
"amount": 5
},
{
"country": "wa",
"amount": 3
},
{
"country": "sc",
"amount": 2
}
],
"CompanyName2": [
{
"country": "wa",
"amount": 3
},
{
"country": "sc",
"amount": 1
}
]
}