How to build map for large json with unknown structure

Tags: , ,



I have large json data with unknown depth and I need to build a map in the following format of result.

const json = {
  1: {
    11: {
      111: [{ "111-0": "b" }, { "111-1": [{ "111-1-0": "vs" }] }],
      112: "asasd",
      ...
    },
    12: [{ "12-0": "sd" }],
    ...
  },
  2: [{ "2-0": "sd" }],
  ....
};

const result = {
  "1::11::111::A0::111-0": "b",
  "1::11::111::A1::111-1::A0::111-1-0": "vs",
  "1::11::112": "asasd",
  "1::12::A0::12-0": "sd",
  "2::A0::2-0": "sd",
};

I think recursion is a good way to solve this but I am not able to implement recursion properly.

This is my current progress. Which gives incorrect output.

const buildRecursion = (json, r, idx = 0, prev = "") => {
  Object.keys(json).forEach((key) => {
    prev += key + "::";
    if (Array.isArray(json[key])) {
      for (let [i, v] of json[key].entries()) {
        buildRecursion(v, r, i, prev);
      }
    } else if (typeof json[key] === "object") {
      buildRecursion(json[key], r, "", prev);
    } else {
      if (idx === "") {
        r[prev + "::" + key + "::"] = json[key];
      } else {
        r[prev + "::" + key + "::" + "::A" + idx] = json[key];
      }
    }
  });
};

Answer

I’m glad to say, you’re on the right track. All I did was clean up your variables (especialy your handling of prev) and it works fine.

Other notes,

  • use '' instead of "" for strings
  • consider using template strings (backticks) for concatenating strings instead of + when doing so is cleaner (more often than not).
  • I renamed the vars json -> input, r -> output, prev -> key for clarity.

let input = {
    1: {
        11: {
            111: [{"111-0": "b"}, {"111-1": [{"111-1-0": "vs"}]}],
            112: "asasd",
        },
        12: [{"12-0": "sd"}],
    },
    2: [{"2-0": "sd"}],
};

let buildRecursion = (input, output = {}, key = []) => {
    if (Array.isArray(input))
        input.forEach((v, i) =>
            buildRecursion(v, output, [...key, `A${i}`]));
    else if (typeof input === 'object')
        Object.entries(input).forEach(([k, v]) =>
            buildRecursion(v, output, [...key, k]));
    else
        output[key.join('::')] = input;
    return output;
};

let result = buildRecursion(input);
console.log(result);
// {
//  "1::11::111::A0::111-0": "b",
//  "1::11::111::A1::111-1::A0::111-1-0": "vs",
//  "1::11::112": "asasd",
//  "1::12::A0::12-0": "sd",
//  "2::A0::2-0": "sd",
// }


Source: stackoverflow