Tan Guven Tan Guven - 2 months ago 14
JSON Question

Javascript Recursion normalize JSON data

I have a json response and I want to simplify this json data with recursion and reduce. I write a function put i stuck at this point. I want to remove all data element and create a new object without data name.

My json data is like this

[
{
"city": {
"data": {
"id": 649442,
"country_id": 54,
"state_id": 682,
"city_name": "Prague",
"state_name": "Praha"
}
},
"country": {
"data": {
"id": 54,
"data": {
"country_name": "Czech Republic",
"short_country": "CZ",
"olympic_code": "CZE"
}
}
}
}
]


And my function is here:

function normalizeData(object) {
return Object.keys(object).reduce((finalObject, objectKey) => {
if (object[objectKey] && object[objectKey].data) {
finalObject[objectKey] = object[objectKey].data;
if (Array.isArray(finalObject[objectKey].data)) {
finalObject[objectKey] = object[objectKey].data.map(item => {
return normalizeData(item);
});
} else {
finalObject[objectKey] = normalizeData(object[objectKey].data);
}
} else {
finalObject[objectKey] = object[objectKey];
}
return finalObject;
}, {});
};


At the and I am still getting data object. So where am I making mistake. Or is there a better way to do this?

Answer

This is a solution without reduce(), that checks if the object properties are not inherited (hasOwnProperty()), and does a recursion for each property that is an object itself. It the property key is data, then all the values get copied to the parent object and the data key gets deleted from the object afterwards. This is where it gets tricky because the data object can have a data property itself, so this has to be checked and a double recursion needs to be applied.

var jsonStr = `{
    "city": {
        "data": {
            "id": 649442,
            "country_id": 54,
            "state_id": 682,
            "city_name": "Prague",
            "state_name": "Praha"
        }
    },
    "country": {
        "data": {
            "id": 54,
            "data": {
                "country_name": "Czech Republic",
                "short_country": "CZ",
                "olympic_code": "CZE"
            }
        }
    }
}`;

var jo = JSON.parse(jsonStr);

function normalize(obj) {
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (typeof obj[key] === 'object') {
                if (key === 'data') {
                    // check if data object also has a data property
                    if (obj[key].hasOwnProperty('data')) {
                        // double recursion
                        normalize(obj[key]);
                        normalize(obj);
                    }
                    else {
                        // copy all values to the parent
                        // (only if they don't exist in the parent yet)
                        for (var subKey in obj[key]) {
                            if (obj[key].hasOwnProperty(subKey)
                            &&  !obj.hasOwnProperty(subKey)) {
                                obj[subKey] = obj[key][subKey];
                            }
                        }
                        // remove the data key
                        delete obj[key];
                    }
                }
                else {
                    // recursion
                    normalize(obj[key]);
                }
            }
        }
    }
}

normalize(jo);

console.log(jo);

you can use a deep extend to create a copy of the object first and return that one, if you don't want the function to modify the input.

Comments