Search code examples
javascriptfunctional-programminglodash

Transform or normalize nested JSON using lodash


I am trying to transform a nested structure, using the library of lodash, I have achieved the expected result, but they are not functional if the structure changes, so I come to you to help me make more robust the function that transforms the JSON.

the initial structure looks like this

const data = {
  foo: {
    bar: {
      baz: [{ a: 1, b: 2, c: 3 }]
    },
    baz: {
      bar: [{ a: 1, b: 2, c: 3 }]
    },
    foo: {
      bar: [{ a: 1, b: 2, c: 3 }]
    }
  },
  bar: {
    baz: {
      bar: [{ a: 1, b: 2, c: 3 }]
    }
  },
  baz: {
    foo: {
      bar: [{ a: 1, b: 2, c: 3 }]
    }
  }
};

after being transformed

const transform = [
  {
    name: 'barfoo',
    results: [{ a: 1, b: 2, c: 3 }]
  },
  {
    name: 'bazfoo',
    results: [{ a: 1, b: 2, c: 3 }]
  },
  {
    name: 'foofoo',
    results: [{ a: 1, b: 2, c: 3 }]
  },
  {
    name: 'bazbar',
    results: [{ a: 1, b: 2, c: 3 }]
  },
  {
    name: 'foobaz',
    results: [{ a: 1, b: 2, c: 3 }]
  }
];

The idea of the transformation is to join the nested key of the first level with the key of the parent node to generate the value of name in the new object and the value of the object in the 2 level as the value of results

for example for the first iteration of foo object in data

name = key(foo.bar) + key(foo)
results = value(foo.bar.baz)

name = 'barfoo'
results = [{ a: 1, b: 2, c: 3 }]

name = key(foo.baz) + key(foo)
results = value(foo.baz.bar)

name = 'bazfoo'
results = [{ a: 1, b: 2, c: 3 }]

name = key(foo.foo) + key(foo)
results = value(foo.foo.bar)

name = 'foofoo'
results = [{ a: 1, b: 2, c: 3 }]

and so with the other objects that are inside data.


Solution

  • I'm not sure if the structure will ever vary, but I added a few extra test cases so you can see how this will behave in some additional scenarios.

    const data = {
      foo: {
        bar: {
          baz: [{ a: 1, b: 2, c: 3 }]
        },
        baz: {
          bar: [{ a: 1, b: 2, c: 3 }]
        },
        foo: {
          bar: [{ a: 1, b: 2, c: 3 }]
        }
      },
      bar: {
        baz: {
          bar: [{ a: 1, b: 2, c: 3 }]
        }
      },
      baz: {
        foo: {
          bar: [{ a: 1, b: 2, c: 3 }]
        }
      },
      a1: {
        a2: [{ a: 1, b: 2, c: 3 }]
      },
      b1: [{ a: 1, b: 2, c: 3 }],
      c1: {
        c2: {
          c3: {
            c4: [{ a: 1, b: 2, c: 3 }]
          }
        },
        c5: [{ a: 1, b: 2, c: 3 }]
      },
      d1: {
        d2: {
            d3: undefined
        }
      },
      e1: {
        e2: {
            e3: null
        }
      },
      f1: {
        f2: {
            // Ignored
        }
      }
    };
    
    function transformObject(object, name) {
        if (!name) {
            name = "";
        }
        return _.flatten(_.map(object, function(value, key) {
            if (typeof value === "undefined" 
                || value === null 
                || _.isArray(value)) {
                return {
                    name: name,
                    results: value
                }
            }
            var objectName = key + name;
            return transformObject(value, objectName);
        }));
    }
    
    transformObject(data);