Как использовать Lodash для объединения двух коллекций на основе ключа?

У меня есть две коллекции, и у объектов есть общий ключ "userId". Как показано ниже:

var _= require('lodash');

var a = [
  { userId:"p1", item:1},
  { userId:"p2", item:2},
  { userId:"p3", item:4}
];

var b = [
  { userId:"p1", profile:1},
  { userId:"p2", profile:2}
];

Я хочу объединить их на основе "userId" для создания:

[ { userId: 'p1', item: 1, profile: 1 },
  { userId: 'p2', item: 2, profile:2 },
  { userId: 'p3', item: 4 } ]

У меня есть до сих пор:

var u = _.uniq(_.union(a, b), false, _.property('userId'));

Результат:

[ { userId: 'p1', item: 1 },
  { userId: 'p2', item: 2 },
  { userId: 'p3', item: 4 },
  { userId: 'p1', profile: 1 },
  { userId: 'p2', profile: 2 } ]

Как я могу слить их сейчас?

Я попробовал _.keyBy, но это приводит к:

{ p1: { userId: 'p1', profile: 1 },
  p2: { userId: 'p2', profile: 2 },
  p3: { userId: 'p3', item: 4 } }

что неверно.

Какой последний шаг я должен сделать?

Ответ 1

Вы можете использовать _.map(), _.assign() и _.find().

// Iterate over first array of objects
_.map(a, function(obj) {

    // add the properties from second array matching the userID
    // to the object from first array and return the updated object
    return _.assign(obj, _.find(b, {userId: obj.userId}));
});

Скриншот

var a = [{
    userId: "p1",
    item: 1
}, {
    userId: "p2",
    item: 2
}, {
    userId: "p3",
    item: 4
}];

var b = [{
    userId: "p1",
    profile: 1
}, {
    userId: "p2",
    profile: 2
}];

var arrResult = _.map(a, function(obj) {
    return _.assign(obj, _.find(b, {
        userId: obj.userId
    }));
});

console.log(arrResult);
document.getElementById('result').innerHTML = JSON.stringify(arrResult, 0, 4);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.1.0/lodash.min.js"></script>
<pre id="result"></pre>

Ответ 2

Ответ с наибольшим количеством голосов не делает правильное слияние. Если второй массив содержит уникальное свойство, он не учитывается.

Этот подход делает правильное слияние.

Lodash

var a = [
  { userId:"p1", item:1},
  { userId:"p2", item:2},
  { userId:"p3", item:4}
];

var b = [
  { userId:"p1", profile:1},
  { userId:"p2", profile:2},
  { userId:"p4", profile:4}
];
var merged = _.merge(_.keyBy(a, 'userId'), _.keyBy(b, 'userId'));
var values = _.values(merged);
console.log(values);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

Ответ 3

Только для полноты: предложение без какой-либо библиотеки.

function merge(a, b, key) {

    function x(a) {
        a.forEach(function (b) {
            if (!(b[key] in obj)) {
                obj[b[key]] = obj[b[key]] || {};
                array.push(obj[b[key]]);
            }
            Object.keys(b).forEach(function (k) {
                obj[b[key]][k] = b[k];
            });
        });
    }

    var array = [],
        obj = {};

    x(a);
    x(b);
    return array;
}

var a = [
        { userId: "p1", item: 1 },
        { userId: "p2", item: 2 },
        { userId: "p3", item: 4 }
    ],
    b = [
        { userId: "p1", profile: 1 },
        { userId: "p2", profile: 2 }
    ],
    c = merge(a, b, 'userId');

document.write('<pre>' + JSON.stringify(c, 0, 4) + '</pre>');

Ответ 4

Lodash имеет метод merge, который работает с объектами (объекты с одним и тем же ключом объединяются). В этой демонстрации массивы a и b сначала преобразуются в объекты (где userId - это ключ), затем объединяются, а результат преобразуется обратно в массив (_.values) (избавление от ключей). _.flatten тогда необходимо, потому что _.values добавляет дополнительный уровень массива.

var u= _({}) // Start with an empty object
  .merge(
    _(a).groupBy("userId").value(),
    _(b).groupBy("userId").value()
  )
  .values()
  .flatten()
  .value();

Ответ 5

Попробуйте демо

var a = [{
    userId: "p1",
    item: 1
}, {
    userId: "p2",
    item: 2
}, {
    userId: "p3",
    item: 4
}];

var b = [{
    userId: "p1",
    profile: 1
}, {
    userId: "p2",
    profile: 2
}];

a.forEach(function (aitem) {
    b.forEach(function (bitem) {
        if(aitem.userId === bitem.userId) {
            _.assign(aitem, bitem);
        }
    });
});

console.log(a);

Ответ 6

ES6+ версия без lodash.

 const array1 = [{ userId: "p1", item: 1 },  { userId: "p2", item: 2 },{ userId: "p3", item: 4 }];
const array2 = [{ userId: "p1", profile: 1 }, { userId: "p2", profile: 2 }];


const result = array1.map(a => ({
  ...a,
  ...array2.find(b => b.userId === a.userId) // _.find(array2, 'skuId') <-- or with lodash 
}));

 document.write('<pre>' + JSON.stringify(result, 0, 2) + '</pre>');