DEV Community

loading...
Cover image for Recursion to update deeply nested objects

Recursion to update deeply nested objects

Nitin Reddy
💡Developer with eager to learn new tech, mainly into JavaScript, Dart, and Python. Loves to create tools for devs.👨‍💻
・2 min read

As a developer, we usually come across a situation wherein we have to update a deeply nested array of objects. For example, say we have an object:

[
    {
        name: 'abc',
        children: [
            {
                name: 'pqr',
                children: [
                    {
                        name: 'xyz',
                        children: []
                    }
                ]
            }
        ]
    },
    {
        name: 'bcd',
        children: [],
    }
]
Enter fullscreen mode Exit fullscreen mode

Alt Text
Photo by Shahadat Rahman on Unsplash

Now in the above array of objects, you have to update the object with the name='xyz', so there are different ways of solving this problem.

  1. Search for some NPM packages or library which does this easily.
  2. Create your method to get this done.

We will opt for option 2 where we are going to use Recursion to solve this problem. Say we know the value of object's key 'name' beforehand where we have to update the children array and we have the array of objects:-

let value = 'xyz';

let list = [
    {
        name: 'abc',
        children: [
            {
                name: 'pqr',
                children: [
                    {
                        name: 'xyz',
                        children: []
                    }
                ]
            },
            {
                name: 'mno',
                children: [
                    {
                        name: 'qrs',
                        children: []
                    }
                ]
            }
        ]
    },
    {
        name: 'bcd',
        children: [],
    }
]

function formatData(arr) {
    arr.forEach(i => {
        if(_.isEqual(i.name, value)) {
            i.children = [...i.children, {
                name: 'New',
                children: []
            }]
        } else {
            formatData(i.children)
        }
    });
}

formatData(list)
Enter fullscreen mode Exit fullscreen mode

Result is

[
   {
      "name":"abc",
      "children":[
         {
            "name":"pqr",
            "children":[
               {
                  "name":"xyz",
                  "children":[
                     {
                        "name":"New",
                        "children":[

                        ]
                     }
                  ]
               }
            ]
         },
         {
            "name":"mno",
            "children":[
               {
                  "name":"qrs",
                  "children":[

                  ]
               }
            ]
         }
      ]
   },
   {
      "name":"bcd",
      "children":[

      ]
   }
]
Enter fullscreen mode Exit fullscreen mode

Here we are iterating over the list and checking whether the current value matches any of the child element's 'name' value and if it does then we update the object or we recursively go inside the array of objects.

What are your thoughts, do you think there is a better way of doing this, then please suggest!

Happy learning and coding !!

Discussion (2)

Collapse
aliplutus profile image
aliplutus • Edited

weel that is realy greate idea to recrsivly update data, but what if I want to resort data. for example, I want to move the element { id: 0, text: "test one" }, to be a sub inside "main". How to do that?

const myData = [
  { id: 0, text: "test one" },
  { id: 1, text: "test tow" },
  { id: 2, text: "test three" },
  {
    id: 3,
    text: "main",
    sub: [
      { id: 4, text: "sub 1" },
      { id: 5, text: "sub 2" },
    ],
  },
];
Enter fullscreen mode Exit fullscreen mode

I tried to do it by deleting the element and then reinsert it wherever the user drop. but when I uncomment state.push(i.item) or state.splice(f + p, 0, i.item); I got error :Maximum call stack size exceeded event when state = state.filter((el) => el.id !== i.item.id); is uncomented as well.

--

Morover, state = [] dons not work as it expected when element == itembeleong to an item inside the main, I which it should convert main to []

and their are more unexpected issues.

function recursiveUpdate(state, action) {
  // state.splice(i, 1);
  //
  const { item, type, i, f, p } = action;
  state.forEach((element) => {
    if (element == item) {
      console.log({ f: state });
      // state.splice(f + p, 0, i.item);
      // state.push(i.item);
      //state = [];
    }
    if (element.id === i.item.id) {
      console.log({ i: state });
      // state = state.filter((el) => el.id !== i.item.id);
    }
    if (element !== i.item && element !== item && element.sub)
      recursiveUpdate(element.sub, action);
  });

  return state;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
r3ndydinar profile image
r3ndyDinar

Thanks Man, Nice Article !

What if I have a case to rename the property of each object. example of the code above, I want to change all properties with the name 'name' to 'title'