Search code examples
javascriptjsonnestedlodash

lodash to flatten JSON and show original path


I have a JSON object with nested children that I would like to flatten and modify using lodash. Ideally the revised JSON will have a value for the original level the nested children were at and show their original path.

Here is sample JSON:

var data = [
    {id: 0, name: 'Australia', children: [
        {id: 10, name: 'Melbourne', children: []},
        {id: 11, name: 'Sydney', children: [
            {id: 100, name: 'Surry Hills', children: []},
            {id: 102, name: 'Darlinghurst', children: []}
        ]},
        {id: 13, name: 'Kambalda', children: []}
    ]},
    {id: 1, name: 'Spain', children: [
        {id: 20, name: 'Barcelona', children: []},
        {id: 21, name: 'Madrid', children: []}
    ]},
    {id: 3, name: 'UK', children: [
        {id: 30, name: 'London', children: [
            {id: 302, name: 'Knightsbridge', children: []},
            {id: 309, name: 'West End', children: []}
        ]},
        {id: 33, name: 'Leeds', children: []},
        {id: 35, name: 'Manchester', children: []}
    ]}
];

And the transformed JSON I would like to generate is:

 [
    {id: 0, name: 'Australia', level: 0, pathname: 'Australia'},
    {id: 10, name: 'Melbourne', level: 1, pathname: 'Australia > Melbourne'},
    {id: 11, name: 'Sydney', level: 1, pathname: 'Australia > Sydney'},
    {id: 100, name: 'Surry Hills', level: 2, pathname: 'Australia > Sydney > Surry Hills'},
    {id: 102, name: 'Darlinghurst', level: 2, pathname: 'Australia > Sydney > Darlinghurst'},
    {id: 13, name: 'Kambalda', level: 1, pathname: 'Australia > Kambalda'},
    {id: 1, name: 'Spain', level: 0, pathname: 'Spain'},
    {id: 20, name: 'Barcelona', level: 1, pathname: 'Spain > Barcelona'},
    {id: 21, name: 'Madrid', level: 1, pathname: 'Spain > Madrid'},
    {id: 3, name: 'UK', level: 0, pathname: 'UK'},
    {id: 30, name: 'London', level: 1, pathname: 'UK > London'},
    {id: 302, name: 'Knightsbridge', level: 2, pathname: 'UK > London > Knightsbridge'},
    {id: 309, name: 'West End', level: 2, pathname: 'UK > London > West End'},
    {id: 33, name: 'Leeds', level: 1, pathname: 'UK > Leeds'},
    {id: 35, name: 'Manchester', level: 1, pathname: 'UK > Manchester'}
]

I have been playing with _.chain, _.flatten and _.pluck and been unable to get anything close.


Solution

  • You can use a simple recursive helper function that would produce an array of arrays, and then use _.flattenDeep to flatten it. This does what you want:

    function flattenMyTree(tree) {
        function recurse(nodes, path) {
            return _.map(nodes, function(node) {
                var newPath = _.union(path, [node.name]);
                return [
                    _.assign({pathname: newPath.join(' > '), level: path.length}, _.omit(node, 'children')),
                    recurse(node.children, newPath)
                ];
            });
        }
        return _.flattenDeep(recurse(tree, []));
    }