What is the best method to consistently convert a deeply nested object into a tabular format that can be easily reversed

Imagine having a deeply nested object with an unknown structure until runtime, like:

    {
      "row-0" : {
        "rec-0" : {
          "date" : 20220121,
          "tags" : [ "val-0" ]
        },
        "rec-1" : {
          "date" : 20220116,
          "url" : "https://example.com/a",
          "tags" : [ "val-0", "val-1" ]
        }
      },
      "row-1" : {
        "rec-0" : {
          "date" : 20220116,
          "url" : "https://example.com/b"
        }
      }
    }

I am seeking a tool or program that can transform this into a tabular (2D) format such as:

    {
      "row-0" : {
        "['rec-0']['date']" : 20220121,
        "['rec-0']['tags'][0]" : "val-0",
        "['rec-1']['date']" : 20220116,
        "['rec-1']['url']" : "https://example.com/a",
        "['rec-1']['tags'][0]" : "val-0",
        "['rec-1']['tags'][1]" : "val-1"
        },
      "row-1" : {
        "['rec-0']['date']" : 20220116,
        "['rec-0']['url'']" : "https://example.com/b"       
      }
    }

This conversion allows for easy exporting as CSV and editing in a spreadsheet application. The keys represent the paths of the original nested object to aid in undoing the transformation.

What would be the most effective way to accomplish this task?

Answer №1

To achieve this, you can utilize a straightforward recursive function that constructs a nested key name and corresponding value, then stores it within an array.

The use of Object.entries becomes essential in this approach as it allows for iterating through either an array or an object, employing the index or key accordingly.

const data = { "row-0": { "rec-0": { date: 20220121, tags: ["val-0"], }, "rec-1": { date: 20220116, url: "https://example.com/a", tags: ["val-0", "val-1"], }, }, "row-1": { "rec-0": { date: 20220116, url: "https://example.com/b", }, }, };

const generateNestedKeyNameAndValue = (input, nestedKeyName, keyValueArr) => {
  if (typeof input === "object") {
    // Iterate over arrays or objects
    const quoteString = Array.isArray(input) ? "" : "'";
    Object.entries(input).forEach(([key, value]) => {
      generateNestedKeyNameAndValue(
        value,
        // Extend the key name 
        `${nestedKeyName}[${quoteString}${key}${quoteString}]`,
        keyValueArr
      );
    });
  } else {
    // Capture string or number (end value)
    keyValueArr.push([nestedKeyName, input]);
  }
};

const output = Object.fromEntries(
  Object.entries(data).map(([key, value]) => {
    const generatedKeyValuePairs = [];
    generateNestedKeyNameAndValue(value, "", generatedKeyValuePairs);
    return [key, Object.fromEntries(generatedKeyValuePairs)];
  })
);

console.log(output);

Answer №2

Traverse through the existing entries by utilizing Array.map(). Formulate the path based on specific rules (refer to the preparePath function). For every value, determine if it is an object (or array). If so, append its keys to the path. Otherwise, return a { [path]: val } structure. Merge all objects by using Object.assign().

// derive the key from the present key, isArray(obj), and the previous path
const preparePath = (key, obj, path = []) => [
  ...path, 
  `[${Array.isArray(obj) ? key : '\'${key}\''}]`
]

// transform all sub objects into a unified object
const fn = (obj, path) => Object.assign({}, ...Object.entries(obj)
  .map(([key, val]) => typeof val === 'object' // if the value is an object
    ? fn(val, preparePath(key, obj, path)) // iterate through it and add to the current path
    : { [preparePath(key, obj, path).join('')]: val } // if the value is not an object, create an object with { [path]: val }
  ))

const data = {"row-0":{"rec-0":{"date":20220121,"tags":["val-0"]},"rec-1":{"date":20220116,"url":"https://example.com/a","tags":["val-0","val-1"]}},"row-1":{"rec-0":{"date":20220116,"url":"https://example.com/b"}}}

// iterate over the top-level of the object and flatten each sub object
const result = Object.fromEntries(
  Object.entries(data).map(([k, v]) => [k, fn(v)])
)

console.log(result)

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

Having trouble displaying a table accurately in React

My goal is to create a table with Material UI in React, similar to the one shown in this image: https://i.stack.imgur.com/QIV8o.png Below is the code I have written so far for this table: return ( <> <div className="main-wrapper& ...

V5 Modal & jQuery: troubleshooting the spinner problem during loading of content

I'm working on displaying a spinner while loading modal content with the use of bootstrap v5 modal and jQuery. However, I encountered some issues in my example. The spinner does not display again after closing the modal; it only shows for the first t ...

Govern Your Gateway with Expressive Logs

I'm facing some issues with the logs in my Express Gateway: Although I followed the documentation and enabled Express Gateway logs, I cannot locate any log files under my gateway root directory. Whenever I start the gateway using the command LOG_L ...

Registration process in Node Express application encounters persistent loading when accessed through Postman

I've been working on a signup model for user accounts in Node.js, but when testing it in Postman, I encountered an issue where there was no response or failure. This left me stuck and I received the following error message in my terminal: Unhandled ...

Is it possible to recreate the initial JavaScript source file using a minified version alongside its associated source-map file?

Currently, I am tackling a project that involves statically analyzing JavaScript code. The challenge lies in the fact that for certain libraries, I am limited to only having a minified version of the file along with its corresponding source-map. Are ther ...

Extracting information from multiple JSON arrays in C#

Searching for statistics in this Json Code is my goal: { "summonerId": 32033681, "modifyDate": 1403658807000, "champions": [{ "id": 40, "stats": { "totalSessionsPlayed": 1, "totalSessionsLost": 0, ...

Restrict the height of posts created in the summernote editor

My goal is to create a structured page application using summernote. When using summernote, a div with contenteditable=true is appended to the body to allow users to add content. However, I want to set a fixed height for this div so that users can only ent ...

Streaming the request body in NodeJS using ExpressJS without buffering

Looking for a solution to process requests with no specified content-type as binary files. const app = express(); app.use(bodyParser.raw({type: (req) => !req.headers['content-type'], limit: '500mb' })); Some of these files can be ...

Utilize recursive and for loop methods for parsing JSON efficiently

I have a JSON file that requires parsing. I'm attempting to implement a recursive method for this task. The current JSON data is structured as shown below: Item 01 SubItem 01 InnerSubItem 01 Item 02 SubItem 01 InnerSubItem 01 Unfortunately, t ...

What is the best way to separate a table column into a distinct column at the specified delimiter count?

I successfully wrote code that splits the third column into new columns at the slash delimiter. However, I am struggling to modify it to split at the nth (i.e. 2nd) occurrence. I couldn't find a solution online, so I'm reaching out here for help ...

Is it normal for the protractor cucumber tests to pass without observing any browser interactions taking place?

Having recently started using protractor cucumber, I have created the following feature. Upon launching protractor protractor.conf.js, the browser opens and immediately closes, displaying that my tests have passed. Is this the expected testing behavior? Sh ...

Navigating with Anchors, Styling and jQuery

Firstly: Apologies in advance for any language errors as English is not my native tongue. :) The Scenario Here's the deal: I'm attempting to create a single button that, when clicked by the user, automatically scrolls down to the next DIV. Each ...

The res.sendFile() function quickly delivers a 204 no content response

Currently, I am facing an issue with using Express' sendFile() function to send an image. The function does not seem to read my file at all and instead returns a 204 no-content response. Below is the code for my function/endpoint: @httpGet('/pri ...

Iterating through JSON arrays using Newtonsoft in C#

Is there a way to iterate through a JSON Array in its pure form using C# and Newtonsoft? [ 78293270, 847744, 32816430 ] Alternatively, can we do the same for an array like this: ["aa", "bb", "cc"] I have searched for answers on SO, but all of the ...

Retrieving the value of an array from a JSON data structure

I am working with the object shown below to extract the desired output. The result will be a new object that represents the final output. var data = { Customer: { Name: "emp1", Departments: [ {Departme ...

Python: "Converting a boolean value to a JSON string with quotes"

Hello everyone, I'm facing a problem with a requirement. Typically, when converting a Python boolean to JSON format, the solution is as follows: >>>data = {'key1': True} >>>data_json = json.dumps(data) >>>print d ...

Adjusting the URL variable based on the selected checkbox option

My mobile website offers users the option of a bright or dark interface using a checkbox styled like an iPhone IOS7 switch. The functionality is working as expected, but I'm now facing an issue with passing the status of the checkbox between pages. I ...

The Shopify JSON array is displaying some results, however, there are also empty results being

I'm trying to retrieve only available results, but the json response is showing null,null,null,result, result. Below is the code snippet: {% capture results %} {% for item in search.results %} {% assign product = item %} {% if product.avail ...

Always display all options in MUI Autocomplete without any filtering

I am seeking to eliminate any filtering in the MUI Autocomplete component. My goal is for the text field popper to display all available options. The results are obtained from a server-side search engine. These results, or "hits," already provide a filter ...

Utilizing jQuery to dynamically update background colors within an ASP repeater based on the selected value of a dropdown list

On my asp.net web page, I have a repeater that displays a table with various fields in each row. I am trying to make it so that when the value of a dropdown within a repeater row changes, the entire row is highlighted in color. While I have achieved this s ...