How to flatten nested object in JavaScript?


Many times, we are in a situation where we are getting data in nested form and want to show it to the user in flatten format. For example, we have the data below

{
  a: {
    c: -98,
    a: "spiderman",
    b: {
      a: 345.67,
      c: {
        a: ["moon knight", "daredevil"],
        b: true,
        c: undefined,
      },
      b: ["dr strange supreme", "hawkeye", "falcon"],
    },
  },
  b: 123,
  c: ["thanos", "deadpool", "quicksilver"],
}

And we want to display it like below

{
  a: [ 'spiderman', 345.67, 'moon knight', 'daredevil' ],
  c: [ -98, undefined, 'thanos', 'deadpool', 'quicksilver' ],
  b: [ true, 'dr strange supreme', 'hawkeye', 'falcon', 123 ]
}

Approach

To achieve the above results, we will traverse the nested object in depth first fashion (we can do it in breadth first also) and store the properties as an array in the resulting flattened object. Below are the steps to solve this problem.

Let NO be the nested object and RO be the resulting object (an empty object passed as a parameter) and FlattenObject is the function which flattens the nested object.

FlattenObject(NO, RO)

                For each key in NO

                                If RO doesn’t have a property with key

                                                RO[key] = []

                                End if

                                If NO[key] is an array

                                                Add the elements of NO[key] to RO[key]

                                Else if NO[key] is an object

                                                Call FlattenObject(NO[key], RO[key])

                                Else

                                                Add NO[key] to RO[key]

                                End if

                End loop

Implementation

Below is the implementation of the above algorithm in JavaScript.

data.js

module.exports.nestedObject = {
  a: {
    c: -98,
    a: "spiderman",
    b: {
      a: 345.67,
      c: {
        a: ["moon knight", "daredevil"],
        b: true,
        c: undefined,
      },
      b: ["dr strange supreme", "hawkeye", "falcon"],
    },
  },
  b: 123,
  c: ["thanos", "deadpool", "quicksilver"],
};

index.js

const { nestedObject } = require("./data");

function getFlattenObject(nestedObject) {
  const flatObject = {};
  flattenObject(nestedObject, flatObject);
  return flatObject;
}

function flattenObject(nestedObject, result) {
  for (let prop in nestedObject) {
    if (!result[prop]) {
      result[prop] = [];
    }

    if (Array.isArray(nestedObject[prop])) {
      result[prop].push(...nestedObject[prop]);
    } else if (typeof nestedObject[prop] === "object") {
      flattenObject(nestedObject[prop], result);
    } else {
      result[prop].push(nestedObject[prop]);
    }
  }
}

console.log(getFlattenObject(nestedObject));