Skip to content Skip to sidebar Skip to footer

Javascript Merge Two Objects Based On Key

I have some objects in the shape of below. [{ product: 'ABC', productId: 'AB123', batch: 'BA1', price: '12' }, { product: 'ABC', productId: 'AB123', bat

Solution 1:

This proposal does not alter the given data.

It creates new objects, first with just single data, later if more data should be grouped, it uses an array for batch and price.

var data = [{ product: 'ABC', productId: 'AB123', batch: 'BA1', price: '12' }, { product: 'ABC', productId: 'AB123', batch: 'BA2', price: '15' }, { product: 'XYZ', productId: 'AB124', batch: 'XY1', price: '124'}],
    merged = [];

data.forEach(function (a) {
    if (!this[a.productId]) {
        this[a.productId] =  { product: a.product, productId: a.productId, batch: a.batch, price: a.price };
        merged.push(this[a.productId]);
        return;
    }
    if (!Array.isArray(this[a.productId].batch)) {
        this[a.productId].batch = [this[a.productId].batch];
    }
    if (!Array.isArray(this[a.productId].price)) {
        this[a.productId].price = [this[a.productId].price];
    }
    this[a.productId].batch.push(a.batch);
    this[a.productId].price.push(a.price);
}, Object.create(null));

console.log(merged);

Solution 2:

You can make use of _.uniqWith to loop over the collection and get rid of duplicates. Apart from that, uniqWith grants you access to the objects themselves so you can tamper them as you like.

In this case, when a duplicate is found, I add its batch and price to the array of the original object, getting the desired result.

var arr = [{
  product: 'ABC',
  productId: 'AB123',
  batch: 'BA1',
  price: '12'
}, {
  product: 'ABC',
  productId: 'AB123',
  batch: 'BA2',
  price: '15'
}, {
  product: 'XYZ',
  productId: 'AB124',
  batch: 'XY1',
  price: '124'
}];

functionaddToArray(val1, val2) {
  return _.isArray(val1) ? val1.concat(val2) : [val1].concat(val2);
}

functionmodifyObjs(a, b) {
  b.batch = addToArray(b.batch, a.batch);
  b.price = addToArray(b.price, a.price);
  returntrue;
}

functionpredicateAndModifier(a, b) {
  return a.product === b.product && a.productId === b.productId && modifyObjs(a, b);
}

console.log(_.uniqWith(arr, predicateAndModifier));
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

Solution 3:

Lodash 4.17.2

_.reduce(data, function(result, item) {
    var added = _.find(result, {
        product: item.product,
        productId: item.productId
    });
    if (_.isObject(added)) {
        //!! better to merge with new object and add result to array again to avoid mutable
        added = _.mergeWith(added, item, function(addedVal, itemVal, key) {
            if (key === 'product' || key === 'productId') {
                return addedVal;
            }
            return _.concat(addedVal, itemVal);
        });
        return result;
    }
    return _.concat(result, item);
}, []);

Solution 4:

You can merge similar objects in the array using a lodash's chain with _.transform() and _.mergeWith():

functionmergeSimilar(arr, arrayProps) {
  // transform the array into a map objectreturn_(arr).transform(function(result, item) { 
    
    // create a temp id that includes the product and productIdvar id = item.product + item.productId; 
    
    // merge the existing item with a new item
    result[id] = _.mergeWith(result[id] || {}, item, function(objValue, srcValue, key) { 
      
      // if a value exists, and it's one of the request keys, concat them into a new arrayif (!_.isUndefined(objValue) && _.includes(arrayProps, key)) {
        return [].concat(objValue, srcValue);
      }
    });
  }, {})
  .values() // get the values from the map object
  .value();
}

var arr = [{
  product: 'ABC',
  productId: 'AB123',
  batch: 'BA1',
  price: '12'
}, {
  product: 'ABC',
  productId: 'AB123',
  batch: 'BA2',
  price: '15'
}, {
  product: 'XYZ',
  productId: 'AB124',
  batch: 'XY1',
  price: '124'
}];

var result = mergeSimilar(arr, ['batch', 'price']);

console.log(result);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

Solution 5:

Does it have to be readable?

var data = [{
    product: 'ABC',
    productId: 'AB123',
    batch: 'BA1',
    price: '12'
}, {
    product: 'ABC',
    productId: 'AB123',
    batch: 'BA2',
    price: '15'
}, {
    product: 'ABC',
    productId: 'AB113',
    batch: 'BA2',
    price: 15
}, {
    product: 'XYZ',
    productId: 'AB124',
    batch: 'XY1',
    price: '124'
}]
var unEs6 = function(x) {
    if (x instanceof Map) {
        var result = {}
        for (let [key, value] of x.entries()) {
            result[key] = unEs6(value);
        }
        return result;
    }
    else {
        return x
    }
}
JSON.stringify(unEs6(
    data
        .map(
            row => (new Map().set(
                row.product, new Map().set(
                    row.productId, new Map()
                        .set("batch", [row.batch])
                        .set("price", [row.price])
                    )
                )
            )
        )
        .reduce((a, b) => !a.has(b.keys().next().value) ?
            new Map([...a, ...b]) :
            !a.get(b.keys().next().value).has(b.get(b.keys().next().value).keys().next().value) ?
                a.set(b.keys().next().value, new Map([
                    ...a.get(b.keys().next().value),
                    ...b.get(b.keys().next().value)
                ])) :
                a.set(b.keys().next().value, a.get(b.keys().next().value).set(
                    b.get(b.keys().next().value).keys().next().value,
                    new Map()
                        .set("batch", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch")
                              .concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch"))
                        )
                        .set("price", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price")
                              .concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price"))
                        )
                ))
        )
))

Post a Comment for "Javascript Merge Two Objects Based On Key"