Ramyachinna
Ramyachinna

Reputation: 483

Iterate nested objects dynamically and push the specific values into separate array using recursion

I am trying java script recursive function that return an array of values based on the key.

The nested JavaScript object has unknown depth. The function is working but the value are not returning properly ..I am getting only first iterated value while I am calling this recursive function from another function. But I can able to console and see the values in same function.

Here is My json

{
    "id": 0,
    "name": "Root Entity",
    "children": [{
        "id": 1,
        "name": "REAT",
        "children": [{
            "id": 2,
            "name": "Business",
            "children": [{
                "id": 3,
                "name": "Region 1",
                "children": [{
                    "id": 5,
                    "name": "Area 1",
                    "children": [
                    {
                        "dealerId": 14,
                        "name": "lead 1"
                    }, 
                    {
                        "dealerId": 15,
                        "name": "lead 2"
                    }, 
                    {
                        "dealerId": 16,
                        "name": "lead 3"
                    }, 
                    {
                        "dealerId": 17,
                        "name": "lead 4"
                    }, 
                    {
                        "dealerId": 18,
                        "name": "lead 5"
                    }, 
                    {
                        "dealerId": 19,
                        "name": "lead 6"
                    }, {
                        "dealerId": 20,
                        "name": "lead 7"
                    }],
                    "kpi_1_met": 0,
                    "lead_num": 0,
                }, {
                    "id": 6,
                    "name": "Area 2",
                    "children": [{
                        "dealerId": 31
                        "name": "lead 1"
                    }] 
                }]
            }]
        }]
    }]

}

Here is the recursion function I have tried

async function outputArray(output, leadInfo, req, res) {
    let resoutput = output.children,
        constructedArray = [],
        obj = {};
        // dealerName, entityList = await entityNames(req, res);
    let leagueData = [];

    resoutput.forEach((dataArray) => {
        if (dataArray.hasOwnProperty('children') &&
            dataArray.children instanceof Array &&
            dataArray.children.length > 0) {
            // console.log("================ dataArray.children", dataArray.children[0]['name']);
            for (let i in dataArray.children) {
                obj = { 'regionId': dataArray.children[i].id, 'region': dataArray.children[i].name};
                outputArray(dataArray.children[i], leadInfo, req, res);
                leagueData.push(obj);
                // console.log("================ leagueData ===============", leagueData);
            }

        } else {
            if (dataArray.hasOwnProperty('name'))
                // console.log("================ else", dataArray.name);
        }
    });
    // console.log("================ leagueData outside =============", leagueData);
    return leagueData;
}

And I am calling the above recursive function in another function that is below

async function dataTable(output, leadInfo, req, res) {
    let obj = {},
        data = await outputArray(output, leadInfo, req, res, obj);

    // here First Iterated data only coming
    // console.log("data from data Table", data)
}    

Output Should be

[ 
  { regionId: 3, areaId: 5, dealerId: 14, name: 'lead 1', region: 'Region 1', area: 'Area 1' }, 
  { regionId: 3, areaId: 5, dealerId: 31, name: 'lead 1', region: 'Region 1', area: 'Area 2' } 
]

It should be populated based on the hierarchy of the tree

Kindly anyone please help me on this. I am trying hard to get it out.

Upvotes: 0

Views: 865

Answers (4)

Scott Sauyet
Scott Sauyet

Reputation: 50807

It's not entirely clear to me if this is what you're looking for, but here is a technique that will flatten out the hierarchy, compressing ancestor name/ids into properties of the leaf nodes:

const nameToKey = (name) => 
  name .replace(/\s*\d+$/, '') .toLowerCase ()

const flattenHierarchy = (node, desc = {}, {name, id, children} = node) =>
  children && children .length > 0
    ? children .flatMap (child => flattenHierarchy (child, {
        ...desc,
        [nameToKey (name)]: name,
        [nameToKey (name) + 'Id']: id
      }))
    : [{...desc, ...node}]

const data = {"children": [{"children": [{"children": [{"children": [{"children": [{"dealerId": 14, "name": "lead 1"}, {"dealerId": 15, "name": "lead 2"}, {"dealerId": 16, "name": "lead 3"}, {"dealerId": 17, "name": "lead 4"}, {"dealerId": 18, "name": "lead 5"}, {"dealerId": 19, "name": "lead 6"}, {"dealerId": 20, "name": "lead 7"}], "id": 5, "kpi_1_met": 0, "lead_num": 0, "name": "Area 1"}, {"children": [{"dealerId": 31, "name": "lead 1"}], "id": 6, "name": "Area 2"}], "id": 3, "name": "Region 1"}], "id": 2, "name": "Business"}], "id": 1, "name": "REAT"}], "id": 0, "name": "Root Entity"}

console .log (flattenHierarchy (data))

This generates an array of objects that look like this:

  {
    "root entity": "Root Entity",
    "root entityId": 0,
    "reat": "REAT",
    "reatId": 1,
    "business": "Business",
    "businessId": 2,
    "region": "Region 1",
    "regionId": 3,
    "area": "Area 1",
    "areaId": 5,
    "dealerId": 14,
    "name": "lead 1"
  }

In the base case, when we're at a leaf node in the children -> children -> children hierarchy, we return the object we've built up with all of the leaf node's properties appended to it. If we're not on a leaf, then we append the current name/id property to our working object, and recursively call the function on each child using this enhanced working object, then flatMap their results into a single array.

This does not entirely match your suggested output. Firstly, there are more results, one for each leaf node in your input. I'm guessing that this is fine, that you were just providing samples and not the full expected result. If not, by what criteria do you choose the nodes to return? Secondly, there are several additional properties from the hierarchy included here, things like reatId and root entity. If you don't want these in the output, how do you decide to exclude them?

Finally, although I took a stab at converting the names into useful keys, it's guesswork, and it feels off. Transforming a string data value to an object key worries me; but perhaps it's just what you want.

Upvotes: 0

VISHNU
VISHNU

Reputation: 966

I am not sure I get the question correctly. If you just want to iterate in the data and push that to an array the below code will help.

<script>
var data = {
    "id": 0,
    "name": "Root Entity",
    "children": [{
        "id": 1,
        "name": "REAT",
        "children": [{
            "id": 2,
            "name": "Business",
            "children": [{
                "id": 3,
                "name": "Region 1",
                "children": [{
                    "id": 5,
                    "name": "Area 1",
                    "children": [
                    {
                        "id": 14,
                        "name": "lead 1"
                    }, 
                    {
                        "id": 15,
                        "name": "lead 2"
                    }, 
                    {
                        "id": 16,
                        "name": "lead 3"
                    }, 
                    {
                        "id": 17,
                        "name": "lead 4"
                    }, 
                    {
                        "id": 18,
                        "name": "lead 5"
                    }, 
                    {
                        "id": 19,
                        "name": "lead 6"
                    }, {
                        "id": 20,
                        "name": "lead 7"
                    }],
                    "kpi_1_met": 0,
                    "lead_num": 0
                }, {
                    "id": 6,
                    "name": "Area 2",
                    "children": [{
                        "id": 31,
                        "name": "lead 1"
                    }] 
                }]
            }]
        }]
    }]

}
let leagueData = [];
function outputArray(output, leadInfo, req, res) {
    let resoutput = output.children,
        obj = { 'regionId': output.id, 'region': output.name};                
        leagueData.push(obj);
        if (output.hasOwnProperty('children') &&
            output.children instanceof Array &&
            output.children.length > 0) {            
            for (let i in output.children) {                
                console.log("*************** leagueData ===============", output.children[i]);
                outputArray(output.children[i], leadInfo, req, res);
            }

        }

}
 function dataTable(output, leadInfo, req, res) {
    let obj = {},
        data =  outputArray(output, leadInfo, req, res, obj);
    // here First Iterated data only coming
     console.log("data from data Table", leagueData)
} 
dataTable(data,"","","");
</script>

Upvotes: 0

Rahul Patil
Rahul Patil

Reputation: 493

This is might you are looking for

let a = {
    "id": 0,
    "name": "Root Entity",
    "children": [{
        "id": 1,
        "name": "REAT",
        "children": [{
            "id": 2,
            "name": "Business",
            "children": [{
                "id": 3,
                "name": "Region 1",
                "children": [{
                    "id": 5,
                    "name": "Area 1",
                    "children": [
                    {
                        "id": 14,
                        "name": "lead 1"
                    }, 
                    {
                        "id": 15,
                        "name": "lead 2"
                    }, 
                    {
                        "id": 16,
                        "name": "lead 3"
                    }, 
                    {
                        "id": 17,
                        "name": "lead 4"
                    }, 
                    {
                        "id": 18,
                        "name": "lead 5"
                    }, 
                    {
                        "id": 19,
                        "name": "lead 6"
                    }, {
                        "id": 20,
                        "name": "lead 7"
                    }],
                    "kpi_1_met": 0,
                    "lead_num": 0,
                }, {
                    "id": 6,
                    "name": "Area 2",
                    "children": [{
                        "id": 31,
                        "name": "lead 1"
                    }] 
                }]
            }]
        }]
    }]

}


function test(data) {
            let response = [];
            if (Array.isArray(data)) {
                for (let o of data) {
                    response.push({ id: o.id, name: o.name });
                    if (o.hasOwnProperty('children') && o.children.length > 0) {
                        let child = test(o.children);
                        response = response.concat(child);
                    }
                }
            } else {
                response.push({ id: data.id, name: data.name });
                if (data.hasOwnProperty('children') && data.children.length > 0) {
                    let child = test(data.children);
                    response = response.concat(child);
                }
            }
            return response;
        }
   
        let res = test(a);
        console.log(res)

Upvotes: 1

A Ralkov
A Ralkov

Reputation: 1044

You should save result of recursive call

outputArray(dataArray.children[i], leadInfo, req, res);

Upvotes: 0

Related Questions