Home > OS >  How to convert a array of object into nested array of objects in Javascript?
How to convert a array of object into nested array of objects in Javascript?

Time:07-25

Hi I am having an array of objects like this

[
    {
      "managerName":  "Ramani",
      "name": "Suresh",
      "goalName": "",
      "subRows": [
        {
          "managerName":  "",
          "name": "",
          "goalName": "Retirement1"
        },
        {
          "managerName":  "",
          "name": "",
          "goalName": "Save For Child Education"
        }
      ]
    },
    {
      "managerName":  "Ramani",
      "name": "Lakshmi",
      "goalName": "Save for Investment"
    },
    {
        "managerName":  "Kamal",
        "name": "John",
        "goalName": "",
        "subRows": [
          {
            "managerName":  "",
            "name": "",
            "goalName": "Loan Repayment"
          },
          {
            "managerName":  "",
            "name": "",
            "goalName": "Car Loan"
          }
        ]
      }
]

is it possible to convert the above data into a format like this below? Here in the below data you can see that the data is structured based on the manager's name.

e.g Ramani (Manager) has repeated two objects. So the data is combined into subRows and the manager name is created as a key at the top.

Expected Data Format

[
    {
      "managerName": "Ramani",
      "name": "",
      "goalName": "",
      "subRows": [
        {
          "managerName": "",
          "name": "Suresh",
          "goalName": "",
          "subRows": [
            {
              "managerName": "",
              "name": "",
              "goalName": "Retirement1"
            },
            {
              "managerName": "",
              "name": "",
              "goalName": "Save For Child Education"
            }
          ]
        },
        {
          "managerName": "",
          "name": "Lakshmi",
          "goalName": ""
        }
      ]
    },
    {
      "managerName": "Kamal",
      "name": "",
      "goalName": "",
      "subRows": [
        {
          "managerName": "",
          "name": "John",
          "goalName": "",
          "subRows": [
            {
              "managerName": "",
              "name": "",
              "goalName": "Loan Repayment"
            },
            {
              "managerName": "",
              "name": "",
              "goalName": "Car Loan"
            }
          ]
        }
      ]
    }
  ]

Why I am doing this because I am creating a table using @tanstack/react-table with multi-level nested expansion. For that table to support that expansion it requires the data needs to be formatted like the one in the above. You can see the working demo of the table in this link - https://codesandbox.io/s/tanstack-table-expansion-sub-level-poryuv?file=/src/App.js

And please let me know If it's possible to frame the data ( expected format ) from the data ( provided at the top )? If that's possible could you help me with the solution

var data=[
    {
        "managerName":"kumar",
        "name": "dhanush",
        "goals": ["goal 1","goal 2"]
    },
    {
        "managerName":"Test",
        "name": "kumar",
        "goals": ["goal 3", "goal 4"]
    },
    {
        "managerName":"lorem",
        "name": "test",
        "goals": ["goal 5"]
    }
]

const result = data.map(({ managerName,name, goals, goalAmount }) => {
  return goals.length === 1
    ? { managerName,name, goals: goals[0]}
    : {
        managerName,
        name,
        goals: '',
        subRows: goals.map(
          (goal, i) => ({ managerName:'',name: '', goal })
        )
    };
});

console.log(result)


Here I converted the API returned data to the first data format. Using the above-defined function but not able to convert to the desired output.

Simplified Question

Given Data

[
    {
        "group_id": 1,
        "name":"Dhanush",
        "age":27
    },
    {
        "group_id": 1,
        "name":"Dharma",
        "age":24
    },
    {
        "group_id": 2,
        "name":"Lorem",
        "age":23
    }
]

Output

[
    {
        "group_id":1,
        "details":[
            {
                "name":"Dhanush",
                "age": 27
            },
            {
                "name":"Dharma",
                "age": 24
            }
        ]
    },
    {
        "group_id": 2,
        "details": [
            {
                "name":"Lorem",
                "age":23
            }
        ]
    }
]

CodePudding user response:

It seems, from the example you posted, that it should be doable, but in my opinion both the original as well as the desired format are badly constructed and have a lot of potentially unnecessary and confusing duplications.

To help you writing a converter it would be very helpful to have a reliable abstract description of both formats.

In my experience it is highly likely if an API provides such confusing data with repetitiv unnecessary elements that it will be hard it not impossible to write a reliable converter based on examples alone.

What will happen for example if the subrow member's first element of your first object ("goalName": "Retirement1") does provide another managerName then 'Ramani'. Is it logically possible? (as structurally it is). If it is possible that Suresh reports to one Manager for one goal and to another for the next (I'm ignoring the nonsensical management structures existing out there..) How would your new structure handle this?

CodePudding user response:

you can do that... with an array reduce:

const data = 
  [ { managerName: 'Ramani', name: 'Suresh',  goalName: '', subRows: 
      [ { managerName: '', name: '', goalName: 'Retirement1'              } 
      , { managerName: '', name: '', goalName: 'Save For Child Education' } 
    ] } 
  , { managerName: 'Ramani', name: 'Lakshmi', goalName: 'Save for Investment' } 
  , { managerName: 'Kamal',  name: 'John',    goalName: '', subRows: 
      [ { managerName: '', name: '', goalName: 'Loan Repayment' } 
      , { managerName: '', name: '', goalName: 'Car Loan'       } 
  ] } ] 


const arrExpected = data.reduce((acc,row) =>
  {
  if (row.managerName !== acc.level1.name)
    {
    let newRow1 =  { managerName: row.managerName,  name: '', goalName: '', subRows:[] }
    acc.result.push( newRow1 )
    acc.level1.name = row.managerName
    acc.level1.arr  = newRow1.subRows
    }
  let newRow2 = { managerName: '',  name: row.name, goalName: ''}

  if (row.subRows) 
    {
    acc.level2.arr = newRow2.subRows = []
    }
  acc.level1.arr.push( newRow2 )

  if (row.subRows)
    {
    row.subRows.forEach( subRow =>
      {
      acc.level2.arr.push( {...subRow})
      })
    }
  return acc
  }
  , { result:[], level1:{name:'',arr:null}, level2:{arr:null}} 
  ).result;


console.log( arrExpected  )
.as-console-wrapper {max-height: 100% !important;top: 0;}
.as-console-row::after {display: none !important;}

  • Related