Recursively Transform my JSON data with JS

I’m trying to figure out how to transform some JSON i’m getting back from a web service so i can easily parse it into a nice type-safe object. I want to transform this format from:

[{
        "name": "AwesomePeople",
        "value": [
            [{
                    "name": "TypeId",
                    "value": 1
                }, {
                    "name": "People",
                    "value": [

                        [{
                                "name": "id",
                                "value": 2
                            }, {
                                "name": "name",
                                "value": "Danno"
                            }
                        ],
                        [{
                                "name": "id",
                                "value": 3
                            }, {
                                "name": "name",
                                "value": "Julio"
                            }
                        ]
                    ]
                }
            ],
            [{
                    "name": "TypeId",
                    "value": 2
                }, {
                    "name": "People",
                    "value": [
                        [{
                                "name": "id",
                                "value": 4
                            }, {
                                "name": "name",
                                "value": "Jenna"
                            }
                        ],
                        [{
                                "name": "id",
                                "value": 5
                            }, {
                                "name": "name",
                                "value": "Coolio"
                            }
                        ]
                    ]
                }
            ]
        ]
    }
]

To the following format:

[{
        "AwesomePeople": [
            [{
                    "TypeId": 1,
                }, {
                    "People": [

                        [{
                                "id": 2
                            }, {
                                "firstName":"Danno"
                            }
                        ],
                        [{
                                "id": 3,
                            }, {
                                "firstName": "Julio"
                            }
                        ]
                    ]
                }
            ],
            [{
                    "TypeId": 2
                }, {
                    "People": [
                        [{
                                "id": 4
                            }, {
                                "firstName": "Jenna"
                            }
                        ],
                        [{
                                "id": 5
                            }, {
                                "firstName": "Coolio"
                            }
                        ]
                    ]
                }
            ]
        ]
    }
];

Two main things need to happen, these stupid “name”/”value” pairs need to be swapped at any and all levels. For example, instead of “name”: “id”, “value”: “3”, it would be simply be “id”:3. The values are sometimes are arrays, so they need to processed in a similar way…the depth is variable, so i can’t assume a certain number of levels deep, so i need to keep processing everything recursively.

I have started playing with the following code…you’ll see an empty “newResult” array that i’m trying to build as i traverse the original JSON, taking different action whether i’m currently looking at an object, an array, or a key/property.

let count = 0;
let result = <the original array above>
let newResult = [];
 result.forEach(function(resObj) {
   console.log("STARTING to TRAVERSE HIGHER LEVEL OBJECTS!");
    traverse(resObj);
   count++;
   
   //we're done processing high level objects, so return from this function and enjoy the newResult!
   if (count===result.length) 
     //return from this function
     console.log(newResult);
       console.log("FINISHED PROCESSING HIGHER LEVEL OBJECTS, SO DONE!");
   
  });


//Below are the functions for traversing 
function traverse(x, level) {
  if (isArray(x)) {
    console.log("array");
    traverseArray(x);
  } else if ((typeof x === 'object') && (x !== null)) {
    console.log("object");
    traverseObject(x);
  } else {
     console.log("property: "+x);
     //console.log(level + x);
  }
}

function isArray(o) {
  return Object.prototype.toString.call(o) === '[object Array]';
}

function traverseArray(arr, level) {
  //console.log(level + "<array>");
  arr.forEach(function(x) {
    traverse(x);
  });
}

function traverseObject(obj, level) {
  var keyName, keyValue;
  //console.log(level + "<object>");
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (key==="name"){
        keyName = obj[key];
        
      }else if (key==="value"){
        keyValue = obj[key];
      }
      if (keyName && keyValue){
        var newObj = {[keyName]: keyValue}
        newResult.push(newObj);
        //console.log("the KEY NAME IS: "+ keyName + ", and the VALUE is: "+keyValue);
      }
      //if we have a key value, but the value is an array, stop and 
     // if (isArray(newOj)
      console.log("traversing..." +obj[key]);
      
      traverse(obj[key]);
    }//end if property
  }//end foreach key in object
  
}//end traverseObject

thanks all…kudos to the person who can get their brain around this 🙂

Answer

You can do this with JSON.stringify and JSON.parse – with a reviver, check if the value has a name property, and if it does, return { [value.name]: value.value }:

const arr=[{name:"AwesomePeople",value:[[{name:"TypeId",value:1},{name:"People",value:[[{name:"id",value:2},{name:"name",value:"Danno"}],[{name:"id",value:3},{name:"name",value:"Julio"}]]}],[{name:"TypeId",value:2},{name:"People",value:[[{name:"id",value:4},{name:"name",value:"Jenna"}],[{name:"id",value:5},{name:"name",value:"Coolio"}]]}]]}];

const result = JSON.parse(JSON.stringify(arr, (key, value) => (
  value?.name
    ? { [value.name]: value.value }
    : value
)));
console.log(result);

If you also want to change the name values to firstName keys, add a conditional in the computed property:

const arr=[{name:"AwesomePeople",value:[[{name:"TypeId",value:1},{name:"People",value:[[{name:"id",value:2},{name:"name",value:"Danno"}],[{name:"id",value:3},{name:"name",value:"Julio"}]]}],[{name:"TypeId",value:2},{name:"People",value:[[{name:"id",value:4},{name:"name",value:"Jenna"}],[{name:"id",value:5},{name:"name",value:"Coolio"}]]}]]}];

const result = JSON.parse(JSON.stringify(arr, (key, value) => (
  value?.name
    ? { [value.name === 'name' ? 'firstName' : value.name]: value.value }
    : value
)));
console.log(result);

Manually:

const arr=[{name:"AwesomePeople",value:[[{name:"TypeId",value:1},{name:"People",value:[[{name:"id",value:2},{name:"name",value:"Danno"}],[{name:"id",value:3},{name:"name",value:"Julio"}]]}],[{name:"TypeId",value:2},{name:"People",value:[[{name:"id",value:4},{name:"name",value:"Jenna"}],[{name:"id",value:5},{name:"name",value:"Coolio"}]]}]]}];

const recurse = (val) => {
  if (!val || typeof val !== 'object') return val;
  if (Array.isArray(val)) return val.map(recurse);
  return { [val.name === 'name' ? 'firstName' : val.name]: val.value };
};


const result = recurse(arr);
console.log(result);