Search code examples
javascriptrecursionnested-object

Function to update any value by key in nested object


I want to write a function that takes a keyName, newValue, and object, and returns the object with the updated key/value pair. For example...

Given this data:

const data = {
  token: {
    id: "abcxyz",
    year: "2022"
  },
  order_data: {
    customer: "Jane",
    shipping: {
      country: "US",
      state: "TX"
    }
  }
}

and a function with these arguments:

const updateObject = (keyName, newValue, object) => {
...
}

I want to be able to call:

const newObject = updateObject("customer", "Bob", data);

so that

newObject = {
      token: {
        id: "abcxyz",
        year: "2022"
      },
      order_data: {
        customer: "Bob",
        shipping: {
          country: "US",
          state: "TX"
        }
      }
    }

My current wrong attempt looks like this:

const updateObject = (keyName, newVal, object) => {
  const results = {};
  for (var key in object) {
    if (key === keyName) {
      results = {
        ...object,
        keyName: newVal
      };
    } else {
      results[key] = object[key];
      if (typeof object[key] === "object") {
        updateObject(keyName, newVal, object.key);
      }
    }
  }
  return results
};

I've been digging through posts on recursion and spread operators all day but can't quite get it right. The nested object can be any shape and depth which is throwing me off.


Solution

  • The spread syntax in your function isn't necessary (you already create a new object with results = {}), and keyname creates a .keyname property not one with a dynamic name (same problem in using object.key instead of object[key] - you might want to revisit dot vs bracket notation). But the main problem is that your updateObject function doesn't update the object it was passed, rather it returns a new one - and you need to consider that in your recursive call. So it should be

    function updateObject(keyName, newVal, object) {
      const results = {};
      for (var key in object) {
        if (key === keyName) {
          results[key] = newVal;
        } else if (typeof object[key] === "object" && object[key] !== null) {
          results[key] = updateObject(keyName, newVal, object[key]);
        } else {
          results[key] = object[key];
        }
      }
      return results;
    }