I’m working with an external API in Node.js and receiving a JSON object that appears to be partially stringified. Here is a sample of what I’m getting:
{"2":["{\"1\":{\"3\":{\"1\":0,\"3\":{\"1\":[{\"1\":27,\"2\":{\"2\":\"Some data is not available\"}}]}},\"4\":\"3168034526981006837\"},\"2\":{\"1\":[{\"1\":\"Brand1\",\"2\":1,\"3\":[\"2400\",\"1900\",\"1900\",\"2900\",\"2400\",\"2900\",\"3600\",\"2900\",\"2900\",\"2900\",\"3600\",\"2900\"],\"6\":\"0\",\"200\":{\"1\":[\"2900\",\"0.0\",\"0.20833333333333334\",\"0.0\",\"316003\",\"616827\",\"0.0\"]}},{\"1\":\"Brand2\",\"2\":1,\"3\":[\"246000\",\"165000\",\"201000\",\"246000\",\"246000\",\"301000\",\"301000\",\"301000\",\"301000\",\"246000\",\"301000\",\"301000\"],\"6\":\"0\",\"200\":{\"1\":[\"246000\",\"0.22357723577235772\",\"0.22357723577235772\",\"0.0\",\"\",\"\",\"0.22357723577235772\"]}},{\"1\":\"Brand3\",\"2\":1,\"3\":[\"6600\",\"5400\",\"6600\",\"8100\",\"8100\",\"9900\",\"12100\",\"8100\",\"8100\",\"8100\",\"9900\",\"6600\"],\"6\":\"0\",\"200\":{\"1\":[\"8100\",\"-0.18518518518518517\",\"-0.18518518518518517\",\"0.0\",\"629943\",\"2000000\",\"-0.18518518518518517\"]}}],\"2\":{\"2\":[{\"3\":\"metric4\"},{\"3\":\"metric1\"},{\"3\":\"metric2\"},{\"3\":\"metric3\"},{\"3\":\"bid_min\"},{\"3\":\"metric5\"},{\"3\":\"metric6\"}]},\"3\":{\"1\":{\"1\":\"3\"}}}}","{\"1\":{\"3\":{\"1\":0,\"3\":{\"1\":[{\"1\":27,\"2\":{\"2\":\"Some data may be not available\"}}]}},\"4\":\"3168034526981006837\"},\"2\":{\"2\":[{\"1\":\"255000\",\"2\":{\"1\":2022,\"2\":5},\"3\":\"235938\"},{\"1\":\"172300\",\"2\":{\"1\":2022,\"2\":6},\"3\":\"159533\"},{\"1\":\"209500\",\"2\":{\"1\":2022,\"2\":7},\"3\":\"193668\"},{\"1\":\"257000\",\"2\":{\"1\":2022,\"2\":8},\"3\":\"236771\"},{\"1\":\"256500\",\"2\":{\"1\":2022,\"2\":9},\"3\":\"237411\"},{\"1\":\"313800\",\"2\":{\"1\":2022,\"2\":10},\"3\":\"291502\"},{\"1\":\"316700\",\"2\":{\"1\":2022,\"2\":11},\"3\":\"291567\"},{\"1\":\"312000\",\"2\":{\"1\":2022,\"2\":12},\"3\":\"289137\"},{\"1\":\"312000\",\"2\":{\"1\":2023,\"2\":1},\"3\":\"289713\"},{\"1\":\"257000\",\"2\":{\"1\":2023,\"2\":2},\"3\":\"237667\"},{\"1\":\"314500\",\"2\":{\"1\":2023,\"2\":3},\"3\":\"289775\"},{\"1\":\"310500\",\"2\":{\"1\":2023,\"2\":4},\"3\":\"287316\"}],\"6\":\"257000\"}}"]}
As seen above, \"1\":\"Brand2\" is a stringified JSON object inside the main JSON. I’m having trouble working with this data, as I need to access the values of nested fields.
I’ve tried using JSON.parse() to convert the stringified part to a JavaScript object, but it’s very inconvenient to write code like this const somewhatId= JSON.parse(data[2][0])['1'][0]['2']; it works, but the overall readibility of the code is awful.
How can I properly parse this and work with it as a standard JSON object in Node.js?
>Solution :
You would write a function that recursively traverses the nested object, and when it identifies strings that could be parsed as JSON, it does so, returning the corresponding object. This object could then be fed again to the same function so that even deeper encoded JSON strings will be parsed.
This also means that string properties which can be interpreted as numbers (like "123.456") will be parsed into numbers (123.456). Same for "null", "false", "true"…
Here is an implementation and how you can run it on your example:
function parseNestedJSON(obj) {
if (typeof obj === "string") {
try { // Parse this string as JSON if possible
return parseNestedJSON(JSON.parse(obj));
} catch {} // If not valid JSON, ignore error, and continue
}
if (Array.isArray(obj)) return obj.map(parseNestedJSON);
if (Object(obj) !== obj) return obj; // Primitive
return Object.fromEntries(Object.entries(obj).map(([k, v]) =>
[k, parseNestedJSON(v)]
));
}
// Example input from the question
const response = {"2":["{\"1\":{\"3\":{\"1\":0,\"3\":{\"1\":[{\"1\":27,\"2\":{\"2\":\"Some data is not available\"}}]}},\"4\":\"3168034526981006837\"},\"2\":{\"1\":[{\"1\":\"Brand1\",\"2\":1,\"3\":[\"2400\",\"1900\",\"1900\",\"2900\",\"2400\",\"2900\",\"3600\",\"2900\",\"2900\",\"2900\",\"3600\",\"2900\"],\"6\":\"0\",\"200\":{\"1\":[\"2900\",\"0.0\",\"0.20833333333333334\",\"0.0\",\"316003\",\"616827\",\"0.0\"]}},{\"1\":\"Brand2\",\"2\":1,\"3\":[\"246000\",\"165000\",\"201000\",\"246000\",\"246000\",\"301000\",\"301000\",\"301000\",\"301000\",\"246000\",\"301000\",\"301000\"],\"6\":\"0\",\"200\":{\"1\":[\"246000\",\"0.22357723577235772\",\"0.22357723577235772\",\"0.0\",\"\",\"\",\"0.22357723577235772\"]}},{\"1\":\"Brand3\",\"2\":1,\"3\":[\"6600\",\"5400\",\"6600\",\"8100\",\"8100\",\"9900\",\"12100\",\"8100\",\"8100\",\"8100\",\"9900\",\"6600\"],\"6\":\"0\",\"200\":{\"1\":[\"8100\",\"-0.18518518518518517\",\"-0.18518518518518517\",\"0.0\",\"629943\",\"2000000\",\"-0.18518518518518517\"]}}],\"2\":{\"2\":[{\"3\":\"metric4\"},{\"3\":\"metric1\"},{\"3\":\"metric2\"},{\"3\":\"metric3\"},{\"3\":\"bid_min\"},{\"3\":\"metric5\"},{\"3\":\"metric6\"}]},\"3\":{\"1\":{\"1\":\"3\"}}}}","{\"1\":{\"3\":{\"1\":0,\"3\":{\"1\":[{\"1\":27,\"2\":{\"2\":\"Some data may be not available\"}}]}},\"4\":\"3168034526981006837\"},\"2\":{\"2\":[{\"1\":\"255000\",\"2\":{\"1\":2022,\"2\":5},\"3\":\"235938\"},{\"1\":\"172300\",\"2\":{\"1\":2022,\"2\":6},\"3\":\"159533\"},{\"1\":\"209500\",\"2\":{\"1\":2022,\"2\":7},\"3\":\"193668\"},{\"1\":\"257000\",\"2\":{\"1\":2022,\"2\":8},\"3\":\"236771\"},{\"1\":\"256500\",\"2\":{\"1\":2022,\"2\":9},\"3\":\"237411\"},{\"1\":\"313800\",\"2\":{\"1\":2022,\"2\":10},\"3\":\"291502\"},{\"1\":\"316700\",\"2\":{\"1\":2022,\"2\":11},\"3\":\"291567\"},{\"1\":\"312000\",\"2\":{\"1\":2022,\"2\":12},\"3\":\"289137\"},{\"1\":\"312000\",\"2\":{\"1\":2023,\"2\":1},\"3\":\"289713\"},{\"1\":\"257000\",\"2\":{\"1\":2023,\"2\":2},\"3\":\"237667\"},{\"1\":\"314500\",\"2\":{\"1\":2023,\"2\":3},\"3\":\"289775\"},{\"1\":\"310500\",\"2\":{\"1\":2023,\"2\":4},\"3\":\"287316\"}],\"6\":\"257000\"}}"]};
const result = parseNestedJSON(response);
console.log(result);