Search code examples
javascriptreactjsjsonantddata-manipulation

Manipulate json data to fit in tree data table in ant design


I need to manipulate my API called data to a certain format to show in ant design table (tree data). https://ant.design/components/table/#components-table-demo-tree-data

However, I spent hours and still cannot figure out how I can manipulate the data from API to display in the required format. Below is an example if I am grouping the information based on the projectId.

Each tree will show the projectId, then the information within the tree (the children), will display all the information of the people who is in that project. If a person is in multiple project, then the information will be in all the project that she exist in.

Can anyone please help me on this. How can I manipulate the data to achieve this?

Object gotten from API call that needs to be manipulated:

{
  "data": [
    {
      "email": "alyssayo@xxx.com",
      "permissionIds": null,
      "roleIds": ["raa","baa","caa"],
      "projectIds": ["1aa","3aa"]
    },
    {
      "email": "chiuewww@xxx.com",
      "permissionIds": null,
      "roleIds": ["baa","caa"],
      "projectIds": ["1aa","2aa","3aa"]
    },
    {
      "email": "lalaqq@xxx.com",
      "permissionIds": null,
      "roleIds": ["caa"],
      "projectIds": ["1aa"]
    }
  ],
  "statusCode": 200,
  "succeeded": true,
  "code": "",
  "message": "",
  "additionalInfo": null
}

After manipulation, the data should look something like this:

const data = [
  {
    projectIds: "1aa",
    children: [
      {
        email: "alyssayo@xxx.com",
        permissionIds: null,
        roleIds: ["raa","baa","caa"],
        projectIds: "1aa",
      },
      {
        email: "chiuewww@xxx.com",
        permissionIds: null,
        roleIds: ["baa","caa"],
        projectIds: "1aa",
      },
      {
        email: "lalaqq@xxx.com",
        permissionIds: null,
        roleIds: ["caa"],
        projectIds: "1aa",
      }
    ]
  },
  {
    projectIds: "2aa",
    children: [
      {
        email: "chiuewww@xxx.com",
        permissionIds: null,
        roleIds: ["baa","caa"],
        projectIds: "2aa",
      }
    ]
  },
  {
    projectIds: "3aa",
    children: [
      {
        email: "alyssayo@xxx.com",
        permissionIds: null,
        roleIds: ["raa","baa","caa"],
        projectIds: "3aa",
      },    
      {
        email: "chiuewww@xxx.com",
        permissionIds: null,
        roleIds: ["baa","caa"],
        projectIds: "3aa",
      }
    ]
  }
];

How the table should look like (another example with different attributes and structure):

Before expanding

How the table should look like after expand

Code for the example of how the tree table works:

https://codesandbox.io/s/antd-tree-table-forked-qc995o?file=/index.js


Solution

  • It looks like you just want to do a transformation. In this case you might consider the below solution which uses Array#map and Array#reduce to output the format you need.

    UPDATED SOLUTION

    const projectIdToChildrenDict = apiData.reduce((dict, item) => {
        item.projectIds.forEach(projectId => {
            if (dict[projectId] === undefined) {
                // instantiate empty array if the project id key is not found
                dict[projectId] = [];
            }
            dict[projectId].push(item);
        });
    
        return dict;
    }, {})
    
    const data = Object.keys(projectIdToChildrenDict).map(key => {
        return {
            projectIds: key,
            children: projectIdToChildrenDict[key]
        }
    })
    

    It's not a full solution, but it should get you 90% there.

    The first section projectIdToChildrenDict is using Array#reduce to build an object. This object is like a dictionary (hence the name) where you can look up a projectId and see all of the elements that contained that project Id.

    Then when we are initializing data we are iterating over the previously built dictionary's keys (project ids) using Array#map and returning a new object of the expected output.