Search code examples
javascriptarraysjavascript-objects

Map Nested Object Key To Another Key


Working with the following object, how can the roles => name be added to the sites => userPermission object with the matching roleId?

For example, the userPermission key of the first sites entry would be updated to:

 "userPermission": {
   "roleId": 6,
   "roleName": "Field Representative"
 }

Once the roleName key has been mapped, there is no longer a need for the roles array and it can be removed from the end result as shown in the expected outcome.

const obj = {
  "id": 542,
  "createdAt": "2018-12-06T22:34:12.553Z",
  "sites": [
    {
      "id": 10,
      "siteId": "sixtysixone",
      "edition": "pro",
      "userPermission": {
        "roleId": 6
      }
    },
    {
      "id": 2,
      "siteId": "amplify",
      "edition": "pro",
      "userPermission": {
        "roleId": 4
      }
    }
  ],
  "roles": [
    {
      "id": 6,
      "name": "Field Representative"
    },
    {
      "id": 4,
      "name": "Program Manager"
    }
  ]
};

Expected outcome:

const outcome = {
  "id": 542,
  "createdAt": "2018-12-06T22:34:12.553Z",
  "sites": [
    {
      "id": 10,
      "siteId": "sixtysixone",
      "edition": "pro",
      "userPermission": {
        "roleId": 6,
        "roleName": "Field Representative"
      }
    },
    {
      "id": 2,
      "siteId": "amplify",
      "edition": "pro",
      "userPermission": {
        "roleId": 4
        "roleName": "Program Manager"
      }
    }
  ]
};

I have attempted with a combination of .map and .find, but feel there is a much more simple/readable way to accomplish this.

const outcome = obj.map(o => ({
  ...o,
  sites: o.sites
    .map(s => ({
      ...s,
      roleName: o.roles
        .find(r => r.id === s.roleId).name,
   })),
}));

Solution

  • Create a map of roles:

     const roles = new Map(obj.roles.map(({ id, name }) => [id, { roleId: id, roleName: name }]));
    

    Then you can just look up:

    const outcome = {
      ...obj,
      sites: obj.sites.map(site => ({ 
        ...site,
        userPermission: roles.get(site.userPermission.roleId),
      }),
      roles: undefined,
    };