Jose the hose
Jose the hose

Reputation: 1895

Recursively search for a nested object in array and update its children

I'm trying to recursively search through an array for an object by its unique id, then push an object into its parts array, then return the entire array

For example, this is the array I want to search:

car =    [
    {
        id: 13,
        title: 'Component13',
        parts: [
           {
               id: 784,
               title: 'Component242',
               parts: [

               ]
           },
           {
               id: 9,
               type: 'mitigation',
               parts: [
                      {
                          id: 68,
                          type: 'mitigation22',
                          parts: [

                          ]
                      },
                      {
                          id: 88,
                          type: 'threat',
                          parts: [

                          ]
                      }
                ]
           }
      ]
},
{
    id: 3,
    title: 'Component13',
    parts: [
           {
               id: 60,
               title: 'Component34',
               parts: [

               ]
           },
           {
               id: 51,
               type: 'threat',
               parts: [
                      {
                           id: 38,
                           type: 'mitigation22',
                           parts: [

                           ]
                     }
               ]
          }
      ]
   }
]

And if I wanted to insert this object into the parts child array in id 38:

{
    id: 34,
    title: 'Component211',
    parts: [

    ]
}

... the result should be this:

  ...commented out the first block to save space
 {
    id: 3,
    title: 'Component13',
    parts: [
          {
              id: 60,
              title: 'Component34',
              parts: [

              ]
          },
          {
              id: 51,
              type: 'threat',
              parts:[
                   {
                        id: 38,
                        type: 'mitigation22',
                        parts: [
                             {
                                 id: 34,
                                 title: 'Component211',
                                 parts: [

                                 ]
                            }
                        ]
                  }
            ]
      }
   ]
}

What is the best way to do this considering that I might need to insert an object at any level on the car array?

My feeble attempt:

 const updatePart = (id, obj, car) => {
    for (var i = 0; i < car.length; i++) {
        if (car[i].id == id) {
            car[i].parts.push(obj)
        } else {
            car[i].parts.map(function (item) {
                updatePart(id, obj, item)
            })
        }
        return car
    }
}

car = updateTree(id, obj, car);

Upvotes: 1

Views: 1123

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386560

If you like to get a new array, you could map the objects with new parts properties.

const
    update = (array, id, object) => array.map(o => o.id === id
        ? { ...o, parts: [...o.parts, object] }
        : { ...o, parts: update(o.parts, id, object) }
    );

var car = [{ id: 13, title: 'Component13', parts: [{ id: 784, title: 'Component242', parts: [] }, { id: 9, type: 'mitigation', parts: [{ id: 68, type: 'mitigation22', parts: [] }, { id: 88, type: 'threat', parts: [] }] }] }, { id: 3, title: 'Component13', parts: [{ id: 60, title: 'Component34', parts: [] }, { id: 51, type: 'threat', parts: [{ id: 38, type: 'mitigation22', parts: [] }] }] }],
    result = update(car, 38, { id: 34, title: 'Component211', parts: [] });

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

A mutating approach with a short circuit if the id is found.

const
    update = (array, id, object) => array.some(o => o.id === id
        ? o.parts.push(object)
        : update(o.parts, id, object)
    );

var car = [{ id: 13, title: 'Component13', parts: [{ id: 784, title: 'Component242', parts: [] }, { id: 9, type: 'mitigation', parts: [{ id: 68, type: 'mitigation22', parts: [] }, { id: 88, type: 'threat', parts: [] }] }] }, { id: 3, title: 'Component13', parts: [{ id: 60, title: 'Component34', parts: [] }, { id: 51, type: 'threat', parts: [{ id: 38, type: 'mitigation22', parts: [] }] }] }];

update(car, 38, { id: 34, title: 'Component211', parts: [] });

console.log(car);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

guijob
guijob

Reputation: 4488

Your updatePart is expecting an array, but in your map you are using recursion sending objects. So you don't need to use map (or forEach, which would be best suitable here) at all:

var car=[{id:13,title:"Component13",parts:[{id:784,title:"Component242",parts:[]},{id:9,type:"mitigation",parts:[{id:68,type:"mitigation22",parts:[]},{id:88,type:"threat",parts:[]}]}]},{id:3,title:"Component13",parts:[{id:60,title:"Component34",parts:[]},{id:51,type:"threat",parts:[{id:38,type:"mitigation22",parts:[]}]}]}];


 const updatePart = (id, obj, car) => {
    for (var i = 0; i < car.length; i++) {
        console.log(car[i])
        if (car[i].id == id) {
            car[i].parts.push(obj)
        } else {
                updatePart(id, obj, car[i].parts)
        }
    }
    return car
}

const obj = {
    id: 34,
    title: 'Component211',
    parts: [

    ]
}

car = updatePart(38, obj, car);

console.log(car)

Other errors in your code arereturn car inside loop, you should return after loop completes and you declared updatePart not updateTree.

Upvotes: 0

James
James

Reputation: 22237

Perhaps consider a lookup object to store a flat list of references to the nodes in your tree:

let memo = {};
const buildMemo = (arr) => {
  arr.forEach(item => {
    memo[item.id] = item;
    if (item.parts) buildMemo(item.parts);
  }
};
buildMemo(car);

Now, if you need to do some operation on the node of your car tree with id = 34, you can get a reference from memo[34]. You would need logic to update memo if you add/remove/move nodes from the car array

Upvotes: 0

Related Questions