Skip to content

Updating nested object by path in javascript

Let’s say I have this object:

{
  categories: [
     { name: "My Category", products: [ { name: "My Product", price: 15 }] },
     { name: "Another", products: [ { name: "Movie", price: 25 }, { name: "Cartoon", price: 7.5 } ] },
     { name: "Lastly", subcategories: [ 
            { name: "Food", products: [ { name: "Avocado", price: 1.25} ] }
         ] 
     }
  ]
}

I’d like to be able to update the price in this object through a function call as follows:

update(object, "categories/0/products/0",25) 
// this would change first product in first category

This answer Javascript: how to dynamically create nested objects using object names given by an array is good but does not address the case when there are arrays in the object.

Underscore acceptable.

Note: this answer Javascript: how to dynamically create nested objects INCLUDING ARRAYS using object names given by an array does not cut it because I don’t have array references in that form (products[1])

Answer

You need to slightly modify function from the linked answer

var object = {
  categories: [
     { name: "My Category", products: [ { name: "My Product", price: 15 }] },
     { name: "Another", products: [ { name: "Movie", price: 25 }, { name: "Cartoon", price: 7.5 } ] },
     { name: "Lastly", subcategories: [ 
            { name: "Food", products: [ { name: "Avocado", price: 1.25} ] }
         ] 
     }
  ]
}

function update(obj, keyPath, value) {
   keyPath = keyPath.split('/');  // split key path string
   lastKeyIndex = keyPath.length-1;
   for (var i = 0; i < lastKeyIndex; ++ i) {
     key = keyPath[i];
     
     // choose if nested object is array or hash based on if key is number
     if (!(key in obj)) obj[key] = parseInt(key) !== parseInt(key) ? {}: []
     obj = obj[key];
   }
   obj[keyPath[lastKeyIndex]] = value;
}

console.log(`Original price ${object.categories[0].products[0].price}`);
update(object, "categories/0/products/0/price",25)
console.log(`New price ${object.categories[0].products[0].price}`);