0

i have two objects, a master and a temp the master looks like

{
    "gnome":{
        "child":{
            name:"child",
            race:"gnome"
        },
        "youngling":{
            name:"youngling",
            race:"gnome"
        }
    },
    "human":{...},
    ...
}

and the temp looks like

{
    "gnome":{
        "man":{
            name:"man",
            race:"gnome"
        }
}

what i am trying to do is have the temp be added to the master like

{
    "gnome":{
        "child":{...},
        "youngling":{...},
        "man":{...}
    },
    "human":{...},
    ...
}

what i currently have

let obj = {}
function generateJson() {
        let race = getinput("race").value
        let name = getinput("name").value


        let temp = {}
        temp[`${race}`] = {}
        temp[`${race}`][`${name}`] = {
            name: name,
            race: race
        }

        obj = Object.assign(obj, temp)
}

all it does is empties and override the first duplicate key with the temp value a.e. {gnome:{man:{..}}}

earlier this question was closed because it should have been awnsered with How can I merge properties of two JavaScript objects dynamically? which sadly it didn't, all of the solutions override objects within objects, i want to add to similar keys

Odinh
  • 183
  • 2
  • 15

2 Answers2

2

Based on your example, this should work

<script>
function merge_without_override(master, temp) {
    for(var key in temp) {
    if( !temp.hasOwnProperty(key) )
        continue;
    if(master[key] !== undefined) // key already exists in master.
        continue; 

        master[key] = Object.assign(temp[key]); // key doesnt exist, assign it.
  }
}

var master = {
    "gnome":{
        "child":{
            name:"child",
            race:"gnome"
        },
        "youngling":{
            name:"youngling",
            race:"gnome"
        }
    },
    "human":{}
};
var temp = {
    "gnome":{
        "man":{
            name:"man",
            race:"gnome"
        }
    }
};
console.log("master before merge");
console.log(master);
merge_without_override(master["gnome"], temp["gnome"]);
console.log("master after merge");
console.log(master);

</script>

Output (in jsfiddle):

{
  gnome: {
    child: { ... },
    man: { ... },
    youngling: { ... }
  },
  human: { ... }
}

JsFiddle: https://jsfiddle.net/h10fpcx2/

Niraeth
  • 315
  • 2
  • 4
  • this is a decently small function! and would have loved if this worked, the issue here is that if the top key does not exist it does not add anything, a.e master = {} thanks though! – Odinh Mar 08 '21 at 05:50
1

Chris Ferdinandi wrote a helper for this here;

I've added an updated version below, but wanted to add a fix for my biggest frustration with Object.assign.

It mutates the source material. To fix this, you can add an empty object as the first argument of the deepAssign function, or use function copyDeepAssign below.

// mutates the source material
function deepAssign(...args) {

    // Make sure there are objects to merge
    const len = args.length;
    if (len < 1) return;
    
    const main = args[0];
    if (len < 2) return main

    // Merge all objects into first
    let i = 0,
        curr;
    while (i < len) {
        curr = args[i];
        for (var key in curr) {
            // If it's an object, recursively merge
            // Otherwise, push to key
            if (Object.prototype.toString.call(curr[key]) === '[object Object]') {
                main[key] = deepAssign(main[key] || {}, curr[key]);
            } else {
                main[key] = curr[key];
            }
        }
        i++;
    }

    return main;
}

// Doesn't mutate the source material
function copyDeepAssign(...args) {
    const base = {};
    
    return deepAssign(base, ...args);
}
frankie
  • 201
  • 1
  • 6
  • 1
    thank you, this works bit large but sometimes thats what we need! – Odinh Mar 08 '21 at 05:52
  • 1
    @Odinh Depending on your tolerance for code-golfing, you can use the same helper but only 170 characters: `let dA=(e,...g)=>{let o,r,a=g.length,m=0;if(a<1)return e;for(;m – frankie Mar 15 '21 at 04:49