Search code examples
javascriptarraysecmascript-6ecmascript-5

Convert nested objects containing mixture of arrays and objects into a different structure using Javascript


I am having a nested object that looks like this. This contains nested arrays and objects inside it. It looks like this,

const input = {
  result: {
    data: {
      groupMapper: [
        {
          id: "id123",
          groupName: "Group 1",
          subGroups: []
        },
        {
          id: "id456",
          groupName: "Group 2",
          subGroups: []
        }
      ],
      items: [
        {
          id: "abc",
          itemName: "Item1",
          groupId: "id123",
          isDefault: true,
          value: 1,
          config: {
            saved: true
          }
        },
        {
          id: "def",
          itemName: "Item2",
          groupId: "id456",
          value: 2,
          isDefault: false,
          config: null
        },
        {
          id: "hgi",
          itemName: "Item3",
          groupId: "id123",
          isDefault: true,
          value: 3,
          config: {
            saved: true
          }
        }
      ]
    }
  }
};

I want this grouped with respect to the ids present in groupMapper and items. So basically entries inside items array should be grouped with respect to groupId of the ``groupMapperand should be part of new object in the output result. Also if an entry insideitemshassavedflag true should be put asused: trueafter grouping in the final object, If its null, then add it asfalse`. The properties should be renamed to the following manner in the output result.

https://codesandbox.io/s/heuristic-nova-8flr9o?file=/src/index.js:1542-1759

const output = {
  id123: {
    categoryId: "id123",
    categoryName: "Group 1",
    tiles: [
      {
        tileId: "abc",
        tileName: "Item1",
        groupId: "id123",
        isDefault: true,
        value: 1,
        used: true
      },
      {
        tileId: "hgi",
        tileName: "Item3",
        groupId: "id123",
        isDefault: true,
        value: 3,
        used: true
      }
    ]
  },
  id456: {
    categoryId: "id456",
    categoryName: "Group 2",
    tiles: [
      {
        tileId: "def",
        tileName: "Item2",
        groupId: "id456",
        isDefault: false,
        value: 2,
        used: false
      }
    ]
  }
};

Here there are two entries has groupId id123 and one has id456. Hence tiles will have two entries in the first group and second one has just one entry. Also used flag is made as true because config.saved was true and in the other case its null hence false is put for used

Code that I tried

const { result } = input;
const res = Object.fromEntries(
  Object.entries(result).map(([key, value], index) => {
    return [key, { ...value, tiles: value.items, used: value.items.config }];
  })
);
console.log(res);

Solution

  • You could first create the output structure with empty tiles arrays, based on the groupMapper data.

    Then iterate the input items and populate the associated tiles arrays:

    const input = {result: {data: {groupMapper: [{id: "id123",groupName: "Group 1",subGroups: []},{id: "id456",groupName: "Group 2",subGroups: []}],items: [{id: "abc",itemName: "Item1",groupId: "id123",isDefault: true,value: 1,config: {saved: true}},{id: "def",itemName: "Item2",groupId: "id456",value: 2,isDefault: false,config: null},{id: "hgi",itemName: "Item3",groupId: "id123",isDefault: true,value: 3,config: {saved: true}}]}}};
    
    const {groupMapper, items} = input.result.data;
    const output = Object.fromEntries(groupMapper.map(grp => [grp.id, {
        categoryId: grp.id,
        categoryName: grp.groupName,
        subGroups: grp.subGroups,
        tiles: []
    }]));
    
    for (const item of items) {
        output[item.groupId].tiles.push({
            tileId: item.id,
            tileName: item.itemName,
            groupId: item.groupId,
            isDefault: item.isDefault,
            value: item.value,
            user: !!item.config?.saved
        })
    }
    
    console.log(output);