2

I want to transform the nested JSON structure into a single object, with the dynamic key I tried with below code but it's work only with one level, I need to write some recursive function, that I am struggling to write the code for n level of nested JSON. Please advise.

   data.map((e) => {
   for (let key in e) {
     if (typeof e[key] === "object") {
       for (let onLevel in e[key]) {
         e[key + "." + onLevel] = e[key][onLevel];
       }
     }
   }
 });

Example

Input JSON

[{
  "Id": "0hb3L00000000jkQAA",
  "Name": "P-2797",
  "ContactEncounterId": "0ha3L000000001qQAA",
  "StartTime": "2020-06-27T11:00:00.000Z",
  "EncounterDuration": 25,
  "ContactEncounter": {
    "Name": "Grocery Shopping 17",
    "LocationId": "1313L0000004ENlQAM",
    "Id": "0ha3L000000001qQAA",
    "Location": {
      "Name": "Waitrose",
      "LocationType": "Site",
      "Id": "1313L0000004ENlQAM"
    }
  }
}]

OutPut JSON

[{
  "Id": "0hb3L00000000jkQAA",
  "Name": "P-2797",
  "ContactEncounterId": "0ha3L000000001qQAA",
  "StartTime": "2020-06-27T11:00:00.000Z",
  "EncounterDuration": 25,
  "ContactEncounter.Name": "Grocery Shopping 17",
  "ContactEncounter.LocationId": "1313L0000004ENlQAM",
  "ContactEncounter.Id": "0ha3L000000001qQAA",
  "ContactEncounter.Location.Name": "Waitrose",
  "ContactEncounter.Location.LocationType": "Site",
  "ContactEncounter.Location.Id": "1313L0000004ENlQAM"
}]
EugenSunic
  • 13,162
  • 13
  • 64
  • 86
sarvesh kumar
  • 183
  • 11
  • 2
    That's not [JSON](https://www.json.org/json-en.html). Input and output are both an array with one object -> [What is the difference between JSON and Object Literal Notation?](https://stackoverflow.com/questions/2904131/what-is-the-difference-between-json-and-object-literal-notation) – Andreas Aug 28 '20 at 09:14

2 Answers2

2

As you said, you need to create a recursion to get deeper into the object. Which means, you would have to track the path where you are.

You could solve it in the following way

const input = [{
        "Id": "0hb3L00000000jkQAA",
        "Name": "P-2797",
        "ContactEncounterId": "0ha3L000000001qQAA",
        "StartTime": "2020-06-27T11:00:00.000Z",
        "EncounterDuration": 25,
        "ContactEncounter": {
            "Name": "Grocery Shopping 17",
            "LocationId": "1313L0000004ENlQAM",
            "Id": "0ha3L000000001qQAA",
            "Location": {
                "Name": "Waitrose",
                "LocationType": "Site",
                "Id": "1313L0000004ENlQAM"
            }
        }
    }
];

function merge( source, target = {}, ...parents) {
  for (let [key, value] of Object.entries( source ) ) {
    const path = (parents || []).concat( key );
    if (typeof value === 'object') {
      merge( value, target, ...path );
      continue;
    }
    target[path.join('.')] = value;
  }
  return target;
}

console.log( merge( input[0] ) );

Or in the following way, where you just use Object.assign to assign the results of the deeper search into your current object.

const input = [{
        "Id": "0hb3L00000000jkQAA",
        "Name": "P-2797",
        "ContactEncounterId": "0ha3L000000001qQAA",
        "StartTime": "2020-06-27T11:00:00.000Z",
        "EncounterDuration": 25,
        "ContactEncounter": {
            "Name": "Grocery Shopping 17",
            "LocationId": "1313L0000004ENlQAM",
            "Id": "0ha3L000000001qQAA",
            "Location": {
                "Name": "Waitrose",
                "LocationType": "Site",
                "Id": "1313L0000004ENlQAM"
            }
        }
    }
];

function merge( source, ...parents) {
  const mergedValue = {};
  for (let [key, value] of Object.entries( source ) ) {
    const path = (parents || []).concat( key );
    if (typeof value === 'object') {
      Object.assign( mergedValue, merge( value, ...path ) );
      continue;
    }
    mergedValue[path.join('.')] = value;
  }
  return mergedValue;
}

console.log( merge( input[0] ) );
Icepickle
  • 12,689
  • 3
  • 34
  • 48
  • This works well thanks unless there is null values eg if LocationType: null. Do you have any thoughts on how to handle this with Object.entries? – ak85 Aug 10 '23 at 00:40
  • @ak85 well you could check `if (value === null || value === undefined) { continue; }` and probably ensure that source ain't null or undefined either? – Icepickle Aug 14 '23 at 14:05
-1

Here is another approach by using the second parameter and passing the key when finding a nth level object.

const obj = {
  "Id": "0hb3L00000000jkQAA",
  "Name": "P-2797",
  "ContactEncounterId": "0ha3L000000001qQAA",
  "StartTime": "2020-06-27T11:00:00.000Z",
  "EncounterDuration": 25,
  "ContactEncounter": {
    "Name": "Grocery Shopping 17",
    "LocationId": "1313L0000004ENlQAM",
    "Id": "0ha3L000000001qQAA",
    "Location": {
      "Name": "Waitrose",
      "LocationType": "Site",
      "Id": "1313L0000004ENlQAM"
    }
  }
}


function flattenObj(obj, param) {
  let newObj = {};
  for (let key in obj) {
    if (typeof obj[key] === 'object') {
      newObj = { ...newObj,
        ...flattenObj(obj[key], key + '.')
      }
    } else {
      newObj[param + key] = obj[key]
    }
  }
  return newObj;
}


console.log(flattenObj(obj, ''))
EugenSunic
  • 13,162
  • 13
  • 64
  • 86