Tan
Tan

Reputation: 352

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?

Upvotes: 2

Views: 4557

Answers (2)

Tan
Tan

Reputation: 352

I found my mistake. I have an array on top of the object :) so I fixed the code like this.

export 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;
  }, {});
}

export function normalizeArray(array) {
  return array.map(object => {
    return normalizeData(object);
  })
}

Upvotes: 0

Simon Hänisch
Simon Hänisch

Reputation: 4968

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.

Upvotes: 2

Related Questions