EDIT: Thanks 4 all the great, diverse answers - I chose the solution that worked for me even after I realized that I needed more requirements: I also needed new properties to be added and for it to work with arrays in objects as well.
Here's what I wanna do: Update one object through another one.
Here are some constraints:
- Only properties that the new object has should be updated (and that the original object also has), the other properties should remain unchanged, NOT DELETED
- Nested objects should also be updated in the same way
My Problem is that I don't know how to easily do this for nested objects because typeof x === "object"
also returns true for Date objects for example.
Here's what I got so far:
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
let updateOrignal = (oObj, uObj) => {
for (let prop in uObj) {
if (uObj.hasOwnProperty(prop) &&
oObj.hasOwnProperty(prop)) {
oObj[prop] = uObj[prop];
}
}
};
console.log(originalObj);
updateOrignal(originalObj, updateObj)
console.log(originalObj);
EDIT: Thanks 4 all the great, diverse answers - I chose the solution that worked for me even after I realized that I needed more requirements: I also needed new properties to be added and for it to work with arrays in objects as well.
Here's what I wanna do: Update one object through another one.
Here are some constraints:
- Only properties that the new object has should be updated (and that the original object also has), the other properties should remain unchanged, NOT DELETED
- Nested objects should also be updated in the same way
My Problem is that I don't know how to easily do this for nested objects because typeof x === "object"
also returns true for Date objects for example.
Here's what I got so far:
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
let updateOrignal = (oObj, uObj) => {
for (let prop in uObj) {
if (uObj.hasOwnProperty(prop) &&
oObj.hasOwnProperty(prop)) {
oObj[prop] = uObj[prop];
}
}
};
console.log(originalObj);
updateOrignal(originalObj, updateObj)
console.log(originalObj);
Currently my updated object looks like this:
{
"dateCreated": "2021-02-10T23:00:00.000Z",
"value": "100",
"subObj": {
"val": 90
}
}
My goal:
{
"dateCreated": "2021-02-10T23:00:00.000Z",
"value": "100",
"subObj": {
"count": 55,
"val": 90
}
}
Share
Improve this question
edited Jan 21, 2021 at 11:43
Cold_Class
asked Jan 20, 2021 at 21:04
Cold_ClassCold_Class
3,5046 gold badges51 silver badges92 bronze badges
4
-
1
updateObj.hasOwnProperty(prop)
<= should useuObj
. Probably not the issue, but it is inconsistent. – Taplar Commented Jan 20, 2021 at 21:08 - Your logic is checking if the update object and the original object have the key to update. I understand you don't want to delete keys, but if you require the key to be pre existing in both places, you're never going to add new ones. – Taplar Commented Jan 20, 2021 at 21:09
- @Taplar thx, I corrected it – Cold_Class Commented Jan 21, 2021 at 8:50
- @Taplar I didn' say I want to add new ones, and I don't. But also didn't say that I don't want it, so I get your point, updated my question^^ – Cold_Class Commented Jan 21, 2021 at 8:51
4 Answers
Reset to default 4This is the solution you need (from https://gist.github./ahtcx/0cd94e62691f539160b32ecda18af3d6), actually you can search on google "deep merge" or "recursively merge two javascript objects"
I added ES6 sintax {...obj} to be sure to clone objects before merging them
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
const merge = (target, source) => {
// Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties
for (const key of Object.keys(source)) {
if (source[key] instanceof Object) Object.assign(source[key], merge(target[key], source[key]))
}
// Join `target` and modified `source`
Object.assign(target || {}, source)
return target
}
console.log(merge({ ...originalObj}, {...updateObj}));
You could test the constructor of the values like this:
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
let updateOriginal = (original, patch) => {
Object.entries(patch).forEach(([key, value]) => {
value && value.constructor === Object && patch[key]
? updateOriginal(original[key], patch[key])
: (original[key] = patch[key]);
});
}
updateOriginal(originalObj, updateObj);
console.log(originalObj);
You could use recursive approach with reduce
method and for..in
loop and also check if the type of object is Date
. This solution will not work with arrays and also will not modify original data.
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
function update(o1, o2) {
return Object.entries(o1).reduce((r, e) => {
for (let p in o2) {
if ([o1[p], o2[p]].every(o => typeof o === 'object')) {
r[p] = o2[p] instanceof Date ? o2[p] : update(r[p], o2[p])
} else {
r[p] = o2[p]
}
}
return r
}, { ...o1 })
}
const result = update(originalObj, updateObj)
console.log(result)
This is what worked for me in the past. You can clean it up a little and customize for your purposes but the idea is as follows:
let originalObj = {
dateCreated: new Date(2021, 1, 10),
value: "100",
subObj: {
count: 55,
val: null
}
};
let updateObj = {
dateCreated: new Date(2021, 1, 11),
subObj: {
val: 90
}
};
function mergeDeep(target, source) {
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) {
Object.assign(target, { [key]: {} });
}
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
}
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
console.log(originalObj);
mergeDeep(originalObj, updateObj);
console.log(originalObj);