JavaScript - Combining nested arrays of JSON data into a single object

I'm looking to convert a nested JSON structure into a single object with dynamic keys. I attempted the code below, which only works for one level. I need help writing a recursive function to handle n levels of nesting. Any advice would be appreciated.

   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"
}]

Answer №1

To delve deeper into the object, a recursion must be created to track the path being taken.

One way to solve this is:

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] ) );

Alternatively, you can use Object.assign to assign 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] ) );

Answer №2

Exploring a different strategy involves utilizing the second parameter and passing the key when searching for an object at a specific level.

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, ''))

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Which is better for your website: SSG vs SSR?

Currently, I am diving into Nextjs and constructing a website using this framework. The site includes both public pages, protected routes (like user dashboard, user project details, and general user data), as well as product pages. I have been pondering h ...

Exporting JavaScript formatting in Netbeans is a breeze

Does anyone know how to preserve the formatting for JavaScript in Netbeans 8.1 when exporting? After clicking on the export button and expanding Formatting, I couldn't find any option specifically for JavaScript. I've thought about locating the ...

Is it possible for a property to be null or undefined on class instances?

Consider this TypeScript interface: export interface Person { phone?: number; name?: string; } Does having the question mark next to properties in the interface mean that the name property in instances of classes implementing the interface ca ...

Using Node.js to serialize JSON POST data as an array

Looking to retrieve POST data from my front-end form. Upon using console.log(req.body), I receive the following output: [ { name: 'name', value: 'kevin' } { name: 'email', value: '' }, { name: 'phone' ...

Issue with Webpack throwing 'window undefined' persists despite using the 'use client' configuration in React/Next.js

I've been using Typescript 5, React 18, and Next.js 14 as my tech stack, and I keep encountering similar errors with various libraries. One of the errors I often face is ReferenceError: window is not defined. This error originates from a third-party ...

The specified class is not found in the type 'ILineOptions' for fabricjs

Attempting to incorporate the solution provided in this answer for typescript, , regarding creating a Line. The code snippet from the answer includes the following options: var line = new fabric.Line(points, { strokeWidth: 2, fill: '#999999', ...

Recreating a <select> element and verifying it once more using JS/HTML5

Before I delve into my issue, I would like to offer an apology for any errors in my English. So, the HTML code I am working with looks like this: <body> <div id="container"> <div id="taskList"> <div id="firstTask"> & ...

The DELETE function in express.js with MySQL integration is encountering a problem where it is unable to

As I work on setting up my website, the backend utilizes express.js to send queries to a MySQL Database. However, when attempting to delete rows, no action seems to take place. function establishConnection() { return mysql.createConnection({ multipl ...

Error in NodeJS session: the variable "request" is not defined

Recently, I have started working with NodeJS and I am currently facing an issue while trying to implement sessions in my project. Any assistance or guidance on this matter would be greatly appreciated. Below is the code snippet where the error occurs: va ...

Encountering difficulties in compiling Dynamic HTML with the $compile function

I'm attempting to incorporate dynamic HTML into my code with the following lines: var el = $compile('<a ng-controller=\"tableController\" ng-click=\"open\">...ReadMore</a>')($scope); But I'm encounterin ...

Is there a way to access an HTML element using Vue's methods?

Here is an example of my Vue component structure: <template> ... </template> <script> export default { methods: { buildDescription () { if (!this.description) { const div = document.createEl ...

Organizing data in a database the arrangement way

I'm looking to populate an array with values for "name" and "nickname" extracted from an SQLITE database and then display them in an alert box. This task is part of a JavaScript project developed using Titanium Appcelerator. Below is the code snippe ...

Python Mechanize file uploading capabilities

Hey there! I've been experimenting with mechanize and Python to upload a file to a website. I've had some success so far, but now I'm facing a challenge at the upload page. I understand that mechanize doesn't support JavaScript, but I&a ...

The comparison between local variables and data can result in a significant drop in performance

My current project involves VueJS and Cesium, but I'm facing a performance issue with a significant drop in frame rate. While I have identified the problem area, I am unsure of why this is happening and how to resolve it. export default { name: ...

Endlessly triggering document.execCommand, the JavaScript selectionchange-EventListener seems to have a mind of

I recently implemented an event listener for selectionchange in the following manner: document.addEventListener("selectionchange", function() { highlight(); console.log("selectionchange-triggered"); }, false); After that, I included the code bel ...

I'm encountering an issue in my server.js file where I am unable to read the property 'collection' as it is undefined

I have encountered an error in my code: /home/ubuntu/workspace/server.js:43 db.collection('quotes').find().toArray(function(err, results) { ^ TypeError: Cannot read property 'collection' of undefined at Object.<anonymous> ( ...

Troubleshooting data binding problems when using an Array of Objects in MatTableDataSource within Angular

I am encountering an issue when trying to bind an array of objects data to a MatTableDataSource; the table displays empty results. I suspect there is a minor problem with data binding in my code snippet below. endPointsDataSource; endPointsLength; endP ...

Struggling to click on a dynamic link before it times out

Can someone help me with a puzzling issue I can't seem to solve? I am trying to achieve the following: Whenever a link is clicked (for example: mysite.com/blog/blog-article.html), I want to save the href of that link to a variable. Then, in JavaScri ...

Struggling with TypeScript errors due to React.HTMLProps for HTMLAnchorElement

When trying to extend a React component with React.HTMLProps without explicitly defining onClick in the attribute list, ESLint complains when passing onClick as an attribute while using the component. Here's an example of the code: The React componen ...

Prevent mobile view from activating when zoomed in on the screen

I've built a webpage with a responsive design that adjusts to mobile view on mobile devices or when the screen size is reduced using developer tools. While this functionality works correctly, I have noticed that the design also switches to mobile vie ...