Search code examples
javascriptjsonfor-loopformattingflat-file

Building a tree structure JSON from flat file with JS


So I am pretty new with JS and using loops to get data formatted in a JSON tree from a flat file. I am trying to build an SAP UI5 app and load the data into a tree table.

I have this data

roles: [
    { role: 'JLP', desc: "jlp role", query:"q1" },
    { role: 'JLP', desc: "jlp role", query:"q2" },
    { role: 'JLP', desc: "jlp role", query:"q3" },
    { role: 'DJF', desc: "djf role", query:"q1" },
    { role: 'DJF', desc: "djf role", query:"q2" },
    { role: 'CJ', desc: "CJ role", query:"q1" }
    ]

and I am trying to get it into a structure based on role

{
    "roles": [
        {
            "rolename": "JLP",
            "properties": [
                {
                    "role": "JLP",
                    "desc": "jlp role",
                    "query": "q1"
                },
                {
                    "role": "JLP",
                    "desc": "jlp role",
                    "query": "q2"
                },
                {
                    "role": "JLP",
                    "desc": "jlp role",
                    "query": "q3"
                }
            ]
        },
        {
            "rolename": "DJF",
            "properties": [
                {
                    "role": "DJF",
                    "desc": "djf role",
                    "query": "q1"
                },
                {
                    "role": "DJF",
                    "desc": "djf role",
                    "query": "q2"
                }
            ]
        },
        {
            "rolename": "CJ",
            "properties": [
                {
                    "role": "CJ",
                    "desc": "cj role",
                    "query": "q1"
                }
            ]
        }
    ]
}

I first build the role structure and make the overall data structure:

buildData:function(o){
    //find all types of roles
    var unique= [];
    for(i = 0; i < o.length; i++){
      var rolename = o[i].role;

      if(unique.indexOf(rolename)< 0) unique.push(rolename);
    }
    
    //create data structure
    var datForm ={results:{roles:[]}};
     var prop = {rolename:"",
               properties:[]};
    unique.forEach(function(a,index){
      prop.rolename = a
      datForm.results.roles.push(prop)
      prop = {rolename:"",
               properties:[]};
    });

Where I am struggling is when I try to loop through the data, I am having to hard code the array segments and its not working when I try to use 'i'. Its not clear to me what exactly I need to do to get the data to push the segments when it matches the role in the previously created data structure.

for(i = 0; i < o.length; i++){
      var current = o[i].role;
      var segment = o[i];
     
      if(current === datForm.results.roles[0].rolename) 
        datForm.results.roles[0].properties.push(segment)
      if(current === datForm.results.roles[1].rolename) 
        datForm.results.roles[1].properties.push(segment)
        if(current === datForm.results.roles[2].rolename) 
        datForm.results.roles[2].properties.push(segment)
        }

    //console.log(datForm)
    var oModel = this.getView().getModel();
    oModel.setData(datForm)
    this.getView().byId("TreeTableBasic").bindRows("/results")

This works, but if I use data with less or more roles it basically breaks and wont work. Can you recommend a better approach? Thanks! Here is the example I am working on: https://jsbin.com/kovevej/edit?html,js,output


Solution

  • You can use reduce. The accumulator acts as a key/value store mapping from roles to the object representing that role. We add each input element to the properties array in the correct role object. Finally, we use Object.values() to get just the array of role objects in the accumulator.

    const data = [ { role: 'JLP', desc: "jlp role", query:"q1" }, { role: 'JLP', desc: "jlp role", query:"q2" }, { role: 'JLP', desc: "jlp role", query:"q3" }, { role: 'DJF', desc: "djf role", query:"q1" }, { role: 'DJF', desc: "djf role", query:"q2" }, { role: 'CJ', desc: "CJ role", query:"q1" } ]
    
    const output = {
      roles: Object.values(data.reduce((a, {role, desc, query}) => (
        (a[role] ??= {rolename: role, properties: []})
          .properties.push({role, desc, query}), a), {}))
    }
    
    console.log(output)