1

I plan to merge two objects:

var c = {
    name: "doo",
    arr: [
        {
            id: 1,
            ver: 1
        },
        {
            id: 3,
            ver: 3
        }
    ]
};


var b = {
    name: "moo",
    arr: [
        {
            id: 1,
            ver: 0
        },
        {
            id: 2,
            ver: 0
        }
    ]
};

When using Object.assign({},b,c) what happens is, that the b.arr is simply being replaced with c.arr.

My question is, how do I preserve objects inside the b.arr that are not in c.arr but still merge objects from that array when they match b.arr[0].id === c.arr[0].id. The desired outcome would look like:

{
    name: "doo",
    arr: [
        {
            id: 1,
            ver: 1
        },
        {
            id: 2,
            ver: 0
        },
        {
            id: 3,
            ver: 3
        }
    ]
}

Thanks.

2
  • If you just want "o" property: c.o = b.o;? Commented Mar 24, 2015 at 15:14
  • No. I want objects that are in the b.arr preserved when they are not in c.arr, but merge when they match. Commented Mar 24, 2015 at 15:19

4 Answers 4

2

You could have a look at ArrayUtils.addAll() from the apache commons

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

1 Comment

Oh Sorry. I missread the tag and was thinking about Java. In JavaScript You would have to merge the Arrays and then remove duplicates as posten in stackoverflow.com/questions/1584370/…
1

As soon as you use lodash - you may use a combination of lodash's functions. It may look a bit complex but it's not:

_.assign({}, b, c, function(objectValue, sourceValue, key, object, source) {
  //merging array - custom logic
  if (_.isArray(sourceValue)) {
    //if the property isn't set yet - copy sourceValue
    if (typeof objectValue == 'undefined') {
      return sourceValue.slice();
    } else if (_.isArray(objectValue)) {
      //if array already exists - merge 2 arrays
      _.forEach(sourceValue, function(sourceArrayItem) {
        //find object with the same ID's
        var objectArrayItem = _.find(objectValue, {id: sourceArrayItem.id});
        if (objectArrayItem) {
          //merge objects
          _.assign(objectArrayItem, sourceArrayItem);
        } else {
          objectValue.push(sourceArrayItem);
        }
      });
      return objectValue;
    }
  }
  //if sourceValue isn't array - simply use it
  return sourceValue;
});

See the full demo here.

2 Comments

Thanks. I think I will parametrize the inner function so that you can pass in the key to merge against (so that one can reuse the function for other contexts as well)
Sure, it's up to you :)
0

Try this function:

function mergeArrayObjects (a, b) {
    var tmp, // Temporary array that will be returned
        // Cache values
        i = 0,
        max = 0;

    // Check if a is an array
    if ( typeof a !== 'object' || typeof a.indexOf === 'undefined')
        return false;
    // Check if b is an array
    if ( typeof b !== 'object' || typeof b.indexOf === 'undefined')
        return false;

    // Populate tmp with a
    tmp = a;

    // For each item in b, check if a already has it. If not, add it.
    for (i = 0, max = b.length; i < max; i++) {
        if (tmp.indexOf(b[i]) === -1)
            tmp.push(b[i]);
    }
    // Return the array
    return tmp;
}

JsFiddle here

Note: Because I'm anal, I decided to see if this function is faster than the alternative proposed. It is.

8 Comments

Thanks. I got the same results as you with lodash: var merge = .merge(def,empty, function(a, b) { if (.isArray(a)) { return a.concat(b); } }); The thing is that the resulting array needs to merge objects with same ID.
Well that's not really what you are originally asking. It's not a merge in this case, as there are certain objects being overwritten (b.arr[1] in your example gets overwritten by c.arr[1])
Well, it is a partial merge what I am after: only override if the objects share the same id -> b.arr[0].id === c.arr[0].id, else preserve the other object.
I'm guessing you want the higher ver to take precedence?
I was going to suggest that, but figured for the point of answering your question as is, I will write you a function so you don't have to modify existing data
|
0

Using lodash, I would do something like this:

var first = {
    name: 'doo',
    arr: [
        { id: 1, ver: 1 },
        { id: 3, ver: 3 }
    ]
};

var second = {
    name: 'moo',
    arr: [
        { id: 1, ver: 0 },
        { id: 2, ver: 0 }
    ]
};

_.merge(first, second, function(a, b) { 
    if (_.isArray(a)) {
        return _.uniq(_.union(a, b), 'id');
    } else {
        return a;
    }
});

// →
// {
//   name: 'doo',
//   arr: [
//     { id: 1, ver: 1 },
//     { id: 2, ver: 0 },
//     { id: 3, ver: 3 }
//   ]
// }

The merge() function let's you specify a customizer callback for things like arrays. So we just need to check it it's an array we're dealing with, and if so, use the uniq() and union() functions to find the unique values by the id property.

Comments

Your Answer

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