Home > Software design >  Changing Object Properties that are nested in Arrays and properties that are not
Changing Object Properties that are nested in Arrays and properties that are not

Time:11-16

I am trying to overwrite an object given specific changes to that object. The problem is that the code I have currently is just overwriting the first object in newBody. So the AndroidText object gets replaced with the iphoneText one. I want the AndroidText object to be there and have it replace the iphoneText one.

const deviceChanges = {
        "a": 5,
        "card": {
                "back": [
                    {
                        "key": "iphoneText",
                        "label": "IPHONE",
                        "value": "UPDATED VALUE FOR IPHONE"
                    },
            ]            
        }
    };

    let newBody = {
        "a": 3,
        "card": {
            "back": [
                   {
                    "key": "androidText",
                    "label": "ANDROID",
                    "value": "androidOS"
                   },
                   {
                    "key": "samsungText",
                    "label": "SAMSUNG",
                    "value": "samsungOS"
                   },
                   {
                    "key": "iphoneText",
                    "label": "IPHONE",
                    "value": "iphone"
                   },
                   {
                    "key": "macbookText",
                    "label": "MACBOOK",
                    "value": "macbookOS"
                   }
        ]            
    },
        "c": 8
    };

    const expected = {
        "object": {
            "a": 5,
            "card": {
                "back": [
                    {
                        "key": "androidText",
                        "label": "ANDROID",
                        "value": "androidOS"
                       },
                       {
                        "key": "samsungText",
                        "label": "SAMSUNG",
                        "value": "samsungOS"
                       },
                       {
                        "key": "iphoneText",
                        "label": "IPHONE",
                        "value": "UPDATED VALUE FOR IPHONE"
                       },
                       {
                        "key": "macbookText",
                        "label": "MACBOOK",
                        "value": "macbookOS"
                       }
            ]       
        },
            "c": 8
        }
    };

I have tried this code:

function merge(target, source) {
  for (const [key, value] of Object.entries(source)) {
    if (key in target) {
      if (typeof value === 'object' && typeof target[key] === 'object') {
        merge(target[key], value);
      } else {
        target[key] = value;
      }
    } else {
      // the key in source isn't in the target. add it
      target[key] = value;
    }
  }
  return target;
}

But with this code does not seem to work for this example. It is replacing the "androidText" object with the "iphone" one.. I think its because the first object in the array? How would you fix this?

CodePudding user response:

Here's the original function updated to detect an array being merged. When an array is found, the function is no longer generic; instead, it matches the target array based on matching values for the key prop, and then updates (or adds) the source object:

const deviceChanges = {
  "a": 5,
  "card": {
    "back": [{
      "key": "iphoneText",
      "label": "IPHONE",
      "value": "UPDATED VALUE FOR IPHONE"
    }, ]
  }
};

let newBody = {
  "a": 3,
  "card": {
    "back": [{
        "key": "androidText",
        "label": "ANDROID",
        "value": "androidOS"
      },
      {
        "key": "samsungText",
        "label": "SAMSUNG",
        "value": "samsungOS"
      },
      {
        "key": "iphoneText",
        "label": "IPHONE",
        "value": "iphone"
      },
      {
        "key": "macbookText",
        "label": "MACBOOK",
        "value": "macbookOS"
      }
    ]
  },
  "c": 8
};


console.log(merge(newBody, deviceChanges))

function merge(target, source) {
  return (Array.isArray(target)) ? mergeArray(target, source) : mergeObject(target, source);
}

// just like the original function
function mergeObject(target, source) {
  for (const [key, value] of Object.entries(source)) {
    if (key in target) {
      if (typeof value === 'object' && typeof target[key] === 'object') {
        merge(target[key], value);
      } else {
        target[key] = value;
      }
    } else {
      // the key in source isn't in the target. add it
      target[key] = value;
    }
  }
  return target;
}

// not generic like the object merge, this looks up source objects
// in target by matching key, merges if found, pushes otherwise 
function mergeArray(target, source) {
  source.forEach(s => {
    let t = target.find(obj => obj.key === s.key);
    t ? merge(t, s) : target.push(s);
  })
}

  • Related