Merging two observables when IDs are equal in Angular

Viewed 725

I have the following first array (let's call it organisation array):

[
  {
    "name": "Apple",
    "id": "org1"
  },
  {
    "name": "Microsoft",
    "id": "org2"
  }
]

and the second array is (let's call it unit array):

[
  {
    "organisation_id": "org1",
    "id": "unitId1"
  },
  {
    "organisation_id": "org30",
    "id": "UnitId2"
  }
]

And I want the output to look like this:

[
  {
    "name": "Apple",
    "id": "org1",
    "units": [
        {
          "organisation_id": "org1",
          "id": "unitId1"
        }
      ]
  },
  {
    "name": "Microsoft",
    "id": "org2",
    "units": []
  }
]

And I want to combine these two arrays (per object) into one array of objects, and create a units property when id === organisation_id. This works when I do something like this:

const combOrgUnit: OrganisationAndUnit[] = [];

this.organisations.subscribe(orgList => {
  this.units.subscribe(unitList => {
    for (const org of orgList) {
      const tempComb: OrganisationAndUnit = {organisation: undefined, units: []};
      const tempUnit: Unit[] = [];
      tempComb.organisation = org;
      for (const unit of unitList) {
        if (org.id === unit.organisation_id) {
          tempUnit.push(unit);
          tempComb.units = tempUnit;
        }
      }
      combOrgUnit.push(tempComb);
    }
    console.log(combOrgUnit);
  });
});

This looks like a sloppy way to check for conditions, is there more rxjs way of doing this? I know that there is one using combineLatest and forkJoin both seems to be deprecated.

Any help would be appreciated.

2 Answers
const arr1$ = of([
  {
    "name": "Apple",
    "id": "org1"
  },
  {
    "name": "Microsoft",
    "id": "org2"
  }
])
const arr2$ = of([
  {
    "organisation_id": "org1",
    "id": "unitId1"
  },
  {
    "organisation_id": "org30",
    "id": "UnitId2"
  }
]);

const arr3$ = combineLatest([arr1$, arr2$]).pipe(
  map(([arr1, arr2]) => {
    return arr1.map( item => ({
        name: item.name,
        id: item.id,
        units: arr2.filter(
          unit => unit.organisation_id === item.id
        )
      }))
    }
  )
)

NB: Please note to import combineLatest from rxjs and NOT rxjs/operators. combineLatest from rxjs/operators is deprecated but combineLatest from rxjs is not. The syntax is also important. combineLatest(arr1$, arr1$) is deprecated but combineLatest([arr1$, arr2$]) is not deprecated

I tried one method based on https://stackoverflow.com/a/51933015/3782963.

this.organisations.pipe(
    switchMap((orgList) => {
      return this.units.pipe(
        map((unitList) => {
          const combOrgUnit: OrganisationAndUnit[] = [];

          for (const org of orgList) {
            const tempComb: OrganisationAndUnit = {organisation: undefined, units: []};
            const tempUnit: Unit[] = [];
            tempComb.organisation = org;
            for (const unit of unitList) {
              if (org.id === unit.organisation_id) {
                tempUnit.push(unit);
                tempComb.units = tempUnit;
              }
            }
            combOrgUnit.push(tempComb);
          }

          return combOrgUnit;
        })
      );
    })
  ).subscribe(a => console.log(a));

Make sure to import import {map, switchMap} from 'rxjs/operators'

But @OwenKelvin's answer is much better.

Related