1

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

1
  • by the way, the discrepancy in the code samples above...my bad, i was trying not to confuse people between the "name" key and the actual "name" value...so but i only renamed it to "firstName" in the second code block. @CertainPerformance didn't seem to be phased by that. thx!!! Commented Apr 3, 2021 at 22:03

3 Answers 3

2

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

Sign up to request clarification or add additional context in comments.

1 Comment

Wow, i was totally over thinking it i guess. Excellent job sir.
0

I grabbed your data, quickly wrote a function to convert it, came to post it and realized that my output wasn't at all what you requested. I would just throw it away, except that it seems to me this output is much more useful than what you requested. So if you can use something like this:

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

then this function may help:

const convert = (xs) =>
  Object .fromEntries (
    xs .map (({name, value}) => [
      name, 
      Array .isArray (value) ? value .map (convert) : value
    ])
  )

const data = [{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"}]]}]]}]

console .log (convert (data))
.as-console-wrapper {min-height: 100% !important; top: 0}

If not, well then maybe someone else might get some use out of it.

1 Comment

Scott, actually your format is actually what i wanted...but i didn't know it at the time...!!!! this code allows me to do a JSON.parse(object) as IMyInterface[]....very nice :).
0

Here is an answer using object-scan. This code modifies the original input, which can be significantly faster than rebuilding the structure.

Note that in your input the data is a bit inconsistent: Where does firstName come from? So I've assumed consistency

// const objectScan = require('object-scan');

const data = [{ 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' } ] ] } ] ] } ];

objectScan(['**[*].name'], {
  filterFn: ({ parent }) => {
    const { name, value } = parent;
    delete parent.name;
    delete parent.value;
    parent[name] = value;
  }
})(data);

console.log(data);
// => [ { AwesomePeople: [ [ { TypeId: 1 }, { People: [ [ { id: 2 }, { name: 'Danno' } ], [ { id: 3 }, { name: 'Julio' } ] ] } ], [ { TypeId: 2 }, { People: [ [ { id: 4 }, { name: 'Jenna' } ], [ { id: 5 }, { name: 'Coolio' } ] ] } ] ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.