4

Merging nested objects it overides.

let target = { cache: 
              {curUser:
               { callingName: 'ch sairam', dateOfBirth: undefined, isTempDob: true, knowMarketPrefChange: true, email: '[email protected]', gender: '',  livingIn: 'IN', uid: 'CrzpFL2uboaeGvMxXi5WQKSQsCr1', timeZone: undefined }, 
               names: [ [Object] ],   minPrice: '2500', maxPrice: '50000', market: 'CA', foundLovedOne: false,  }
             }
let source = { cache: 
              {curUser: 
               { isTempDob: true, knowMarketPrefChange: false, timeZone: 'Asia/Kolkata' },
               prefLanguage: 'en', market: 'IN',  minPrice: 2250, maxPrice: 45000, foundLovedOne: false, domainName: 'roo-fire.appspot.com', prodQueryPageNumber: 0, welcomeIntentShown: true }, 
              curContexts: [] }
 target = Object.assign({},target,source);

when print target it results

Object { cache: Object { curUser: Object { isTempDob: true, knowMarketPrefChange: false, timeZone: "Asia/Kolkata" }, prefLanguage: "en", market: "IN",   minPrice: 2250, maxPrice: 45000, foundLovedOne: false,  prodQueryPageNumber: 0, welcomeIntentShown: true }, curContexts: Array [] }

source override target, I want to get this results?

{ cache: 
              {curUser:
               { callingName: 'ch sairam', dateOfBirth: undefined, isTempDob: true, knowMarketPrefChange: false, email: '[email protected]', gender: '', prefMarket: 'CA', livingIn: 'IN', uid: 'CrzpFL2uboaeGvMxXi5WQKSQsCr1', timeZone:'Asia/Kolkata' }, 
               prefLanguage: 'en',names: [ [Object] ], minPrice: '2250', maxPrice: '45000', market: 'CA', foundLovedOne: false, prodQueryPageNumber: 0, welcomeIntentShown: true },
              curContexts: [] }
2

4 Answers 4

11

You could merge all propeties and use a recursive aproach for nested objects.

function merge(a, b) {
    return Object.entries(b).reduce((o, [k, v]) => {
        o[k] = v && typeof v === 'object'
            ? merge(o[k] = o[k] || (Array.isArray(v) ? [] : {}), v)
            : v;
        return o;
    }, a);
}

var target = { cache: { curUser: { callingName: 'ch sairam', dateOfBirth: undefined, isTempDob: true, knowMarketPrefChange: true, email: '[email protected]', gender: '', livingIn: 'IN', uid: 'CrzpFL2uboaeGvMxXi5WQKSQsCr1', timeZone: undefined }, names: [['Object']], minPrice: '2500', maxPrice: '50000', market: 'CA', foundLovedOne: false } },
    source = { cache: { curUser: { isTempDob: true, knowMarketPrefChange: false, timeZone: 'Asia/Kolkata' }, prefLanguage: 'en', market: 'IN', minPrice: 2250, maxPrice: 45000, foundLovedOne: false, domainName: 'roo-fire.appspot.com', prodQueryPageNumber: 0, welcomeIntentShown: true }, curContexts: [] };

console.log([{}, target, source].reduce(merge));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

12 Comments

v && typeof v === 'object' separates between having null or an object which is not null. null is in javascript an object but not truthy.
Why do we assign o[k] with null if v is null? What if o[k] in a , say having a value, then value would be replaced by a null? In other questions, why this recursive would work as in finally merging the results as expected? ? merge(o[k] = o[k] || (Array.isArray(v) ? [] : {}), v)
here it is: every recursion need to hande en end situation where no other call of the funtion takes place. this is here wrapped in a check for having an object (not null) and returning eiter the merged objects or just a value. the return of the value stops the recursion.
@jason, at some end, no object is available, then it returns the single primitive value. maybe it comes more clear, if you replace the ternary with an if statement and return the first ? part and later return the second : part. another if or else is not necessary, because having a return stament before, the rest of the function is always the else part.
@jason, your result is right/expected. i don't kow how loash is implemented. you are welcome.
|
4

Object.assign doesn't do a deep merge. To do a nested merge, I suggest using lodash

import _ = require('lodash');
target = _.merge(source, value2);

Alternately, you can copy both the objects and do an object.assign merge

target =Object.assign({},JSON.parse(JSON.stringify(source)), JSON.parse(JSON.stringify(target)))

Comments

1

You can use this advanced function for object/array deep merge (or deep assign). It's working like a charm.

export function deepAssignJSON(target, source, {isMutatingOk = false, isStrictlySafe = false} = {}) {

    // Returns a deep merge of source into target. Does not mutate target unless isMutatingOk = true.
    target = isMutatingOk ? target : clone(target, isStrictlySafe);
    for (const [key, val] of Object.entries(source)) {
        if (val !== null && typeof val === `object`) {
            if (target[key] === undefined) {
                target[key] = {};
            }

            // Even where isMutatingOk = false,
            // recursive calls only work on clones, so they can always safely mutate --- saves unnecessary cloning
            target[key] = deepAssignJSON(target[key], val, {isMutatingOk: true, isStrictlySafe});
        } else {
            target[key] = val;
        }
    }
    return target;
}

function clone(obj, isStrictlySafe = false) {

    // Clones an object. First attempt is safe. If it errors (e.g. from a circular reference),
    // 'isStrictlySafe' determines if error is thrown or an unsafe clone is returned. 
    try {
        return JSON.parse(JSON.stringify(obj));
    } catch(err) {
        if (isStrictlySafe) { throw new Error() }
        console.warn(`Unsafe clone of object`, obj);
        return {...obj};
    }
}

2 Comments

This simple solution works great
I don’t understand this part: if (target[key] === undefined) { ; if it is undefined. Then shouldn’t the next step is assign value into target[key]? But right now, we only do target[key] = val when val is null, which i found it confusing. In fact shouldn’t we assign nothing when val is null?
0

You could also use Ramda. it's an open source javascript util. which has much less deps that loadash.

And with Ramda, using the mergeDeepRight :

import { mergeDeepRight } from 'ramda';

result = mergeDeepRight(sourceObject, targetObject)

Object assign doesn't take nested values. which is the issue that you having at this moment.

1 Comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.