Back-End holds several databases to whom I need to make API calls on to gather a dataset that I require to display the information. Im using angular 12 and NGRX for state management.
API Requests are cast on to observables.
I'm trying to combine several observable arrays into a single observable array since I don't have an idea of how to pass in multiple objects to a selector and a reducer
So far I'm able to get the data and combine it but the output of getUtilities() instead of an observable array that I could pass to a selector I get several objects that the selctor does not how to deal with.
Redux shows that the action of successfull retreiving the data is executed 4 times. 
My question is - How do I merge the API data into a single utiltiesList array without the need to call the backend several hundred times.
data.service.ts file contains all the API call functions
getActiveProperties(): Observable<Property[]> {
return this.http.get<Property[]>(this.getPropertiesUrl).pipe(
mergeMap((data) => {
return of(data);
})
);
}
getCurrentUtilities(
currentMonth: string,
currentYear: string
): Observable<utilities[]> {
return this.http
.get<utilities[]>(
`${this.getUtiltiesUrl}?month=${currentMonth}&year=${currentYear}`
)
.pipe(
mergeMap((data) => {
return of(data);
})
);
}
getPreviousUtilities(
previousMonth: string,
previousYear: string
): Observable<utilitiesPrevious[]> {
return this.http
.get<utilities[]>(
`${this.getUtiltiesUrl}?month=${previousMonth}&year=${previousYear}`
)
.pipe(
map((response) =>
response.map(
(sp): utilitiesPrevious => ({
propertyID: sp.propertyID,
cold1Prev: sp.cold1,
cold2Prev: sp.cold2,
hot1Prev: sp.hot1,
hot2Prev: sp.hot2,
gasPrev: sp.gas,
electricityPrev: sp.electricity,
})
)
)
);
getUtilityComments(): Observable<utilitiesComments[]> {
return this.http.get<utilitiesComments[]>(`${this.getCommentsUrl}`).pipe(
mergeMap((data) => {
return of(data);
})
);
}
To combine the data I've created this "beautiful" piece of code:
getUtilities(
currentMonth: string,
currentYear: string,
previousMonth: string,
previousYear: string
): Observable<utilitiesList[]> {
const properties = this.getActiveProperties();
const currentUtilities = this.getCurrentUtilities(
currentMonth,
currentYear
);
const previousUtilities = this.getPreviousUtilities(
previousMonth,
previousYear
);
const comments = this.getUtilityComments();
return forkJoin([properties, currentUtilities, previousUtilities, comments])
.pipe(
switchMap((response) => [
...response[0]
.map((item1) => ({
...response[1].find(
(item2) => item2.propertyID === item1.propertyID && item2
),
...item1,
}))
.map((item1) => ({
...response[2].find(
(item2) => item2.propertyID === item1.propertyID && item2
),
...item1,
}))
.map((item1) => ({
...response[3].find(
(item2) => item2.propertyID === item1.propertyID && item2
),
...item1,
})),
])
)
.pipe(map((data: unknown) => <utilitiesList[]>data));
}
Here is a sample set of what the API Calls are returning: getActiveProperties()
[
{
"propertyID": 1,
"AddressL1": "add1",
"AddressL2": "cityA",
"zip": "XXYYYY"
},
{
"propertyID": 2,
"AddressL1": "add2",
"AddressL2": "cityB",
"zip": "XXYYYY"
},
{
"propertyID": 3,
"AddressL1": "add3",
"AddressL2": "cityC",
"zip": "XXYYYY"
},
{
"propertyID": 4,
"AddressL1": "add4",
"AddressL2": "cityD",
"zip": "XXYYYY"
}
]
getCurrentUtilities()
[
{
"utilityID": 77,
"cold1": 169,
"cold2": 145,
"hot1": 153,
"hot2": 153,
"gas": 143,
"electricity": 994,
"month": 8,
"year": 2021,
"propertyID": 4,
"commentID": 4
}
]
getPreviousUtilities()
{
"utilityID": 19,
"cold1": 165,
"cold2": 167,
"hot1": 158,
"hot2": 158,
"gas": 187,
"electricity": 1015,
"month": 7,
"year": 2021,
"propertyID": 1,
"commentID": 1
},
{
"utilityID": 38,
"cold1": 170,
"cold2": 162,
"hot1": 154,
"hot2": 155,
"gas": 119,
"electricity": 1082,
"month": 7,
"year": 2021,
"propertyID": 2,
"commentID": 2
},
{
"utilityID": 57,
"cold1": 148,
"cold2": 176,
"hot1": 175,
"hot2": 139,
"gas": 166,
"electricity": 1065,
"month": 7,
"year": 2021,
"propertyID": 3,
"commentID": 3
},
{
"utilityID": 76,
"cold1": 165,
"cold2": 142,
"hot1": 149,
"hot2": 149,
"gas": 135,
"electricity": 969,
"month": 7,
"year": 2021,
"propertyID": 4,
"commentID": 4
}
]
getUtilityComments
[
{
"propertyID": 1,
"Cold1Com": "Nr.6918",
"Cold2Com": "Nr.5773",
"Hot1Com": "Nr.7719",
"Hot2Com": "Nr.5880",
"GasCom": "Nr.2427",
"ElectCom": "Nr.2744",
"Comment": "Comm1"
},
{
"propertyID": 2,
"Cold1Com": "Nr.8573",
"Cold2Com": "Nr.9652",
"Hot1Com": "Nr.1279",
"Hot2Com": "Nr.3600",
"GasCom": "Nr.1730",
"ElectCom": "Nr.1865",
"Comment": "Comm2"
},
{
"propertyID": 3,
"Cold1Com": "Nr.6214",
"Cold2Com": "Nr.9956",
"Hot1Com": "Nr.8015",
"Hot2Com": "Nr.8445",
"GasCom": "Nr.4348",
"ElectCom": "Nr.4714",
"Comment": "Comm3"
},
{
"propertyID": 4,
"Cold1Com": "Nr.5625",
"Cold2Com": "Nr.7039",
"Hot1Com": "Nr.6681",
"Hot2Com": "Nr.8978",
"GasCom": "Nr.7224",
"ElectCom": "Nr.6826",
"Comment": "Comm4"
}
]
All of the API requests have a common field - propertyID which is a number. Here's the list of interfaces for the respective objects:
export interface utilities {
utilityID: number;
propertyID: number;
cold1: number | null;
cold2: number | null;
hot1: number | null;
hot2: number | null;
gas: number | null;
electricity: number | null;
}
export interface utilitiesPrevious {
cold1Prev: number | null;
cold2Prev: number | null;
hot1Prev: number | null;
hot2Prev: number | null;
gasPrev: number | null;
electricityPrev: number | null;
propertyID: number;
}
export interface utilitiesComments {
propertyID: number;
Cold1Com: string | null;
Cold2Com: string | null;
Hot1Com: string | null;
Hot2Com: string | null;
GasCom: string | null;
ElectCom: string | null;
Comment: string | null;
}
export interface utilitiesList {
utilityID: number;
propertyID: number;
cold1: number | null;
cold2: number | null;
hot1: number | null;
hot2: number | null;
gas: number | null;
electricity: number | null;
cold1Prev: number | null;
cold2Prev: number | null;
hot1Prev: number | null;
hot2Prev: number | null;
gasPrev: number | null;
electricityPrev: number | null;
Cold1Com: string | null;
Cold2Com: string | null;
Hot1Com: string | null;
Hot2Com: string | null;
GasCom: string | null;
ElectCom: string | null;
Comment: string | null;
AddressL1: string | null;
AddressL2: string | null;
zip: string | null;
Tennant_ID: number | null;
Lease_ID: number | null;
Previous_Leases: number | null;
Sold: number | null;
Date_Sold: Date | null;
}