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);