Массивы и объекты Javascript: получите различия и объедините их

1

Поэтому у меня есть такой сценарий, когда у меня есть клиент-приложение, которое отправляет данные (массив объектов) на сервер, который затем пересылает данные другим клиентам, подключенным к этому серверу.

В клиенте-приложении данные постоянно меняются, что означает: изменение значений, появление новых объектов внутри массива, удаление объектов и т.д....

Теперь я хочу, чтобы другие клиенты всегда получали последние данные. И поскольку я не хочу, чтобы клиент-приложение просто выталкивало все новые данные на сервер, а затем пересылало все новые данные другим клиентам, я решил разрешить клиенту-приложению изменять эти изменения (используя эту библиотеку: https://www.npmjs.com/package/deep-object-diff).

Затем другие клиенты получают массив объектов только с данными, которые фактически изменились, и поскольку они знают предыдущий массив данных, я хочу, чтобы они "объединили" массив изменений со старым объектом данных.

Моя реальная проблема - это слияние. Я не знаю, как правильно это сделать. Особенно, если у меня есть массив объектов без ключа для объектов.

Поэтому мои данные выглядят примерно так:

let data = [
  {
    name: 'Peter',
    age: 26,
    sID: 546589995544
  },
  {
    name: 'John',
    age: 33,
    sID: 554589525469
  }
];

На самом деле там гораздо больше, но хорошо, вот и структура.

Поэтому, если библиотека diff написана, это изменения:

let changes = {
  {
    age: 34,
    sID: 554589525469
  }
};

(обратите внимание, что теперь у меня есть объект объектов, а не массив объектов. То, что возвращает библиотека diff-library)

Я хочу, чтобы объединенный объект был

[
  {
    name: 'Peter',
    age: 26,
    sID: 546589995544
  },
  {
    name: 'John',
    age: 34,
    sID: 554589525469
  }
];

(Джон сейчас на год старше)

Поэтому я полностью верю, что это было бы намного проще, если бы у меня был ключ к объектам в качестве идентификатора, но все же я думаю, что для такого сценария должно быть решение. И, как вы можете видеть, свойство sID может действовать как идентификатор, а его просто не ключ.

Если бы кто-то мог указать, как это сделать в обоих случаях (с конкретным ключом для объектов и без него)

  • 0
    Смотрите stackoverflow.com/help/mcve
  • 0
    Теперь код вашего вопроса недействителен ...
Теги:
arrays
merge
javascript-objects
array-difference

4 ответа

1
Лучший ответ

Вы можете использовать .find() чтобы найти объект внутри массива, где значения должны быть изменены, Object.assign() чтобы установить значения

let data = [{
    name: 'Peter',
    age: 26,
    sID: 546589995544
  },
  {
    name: 'John',
    age: 33,
    sID: 554589525469
  }
];

let changes = [{
  age: 34,
  sID: 554589525469
}];

for (let prop of changes) {
  let {sID} = prop;
  Object.assign(data.find(({sID: id}) => id === sID), prop)
}

console.log(data);
  • 0
    Похоже, хороший подход, который вроде работает. Это просто не работает для меня, потому что diff-библиотека не возвращает массив объектов, но объект с объектами в качестве членов. И потом, ваши решения больше не работают, потому что изменения [Symbol.iterator] не является функцией. Любое исправление к этому?
  • 1
    Вы можете использовать Object.values() или Object.entries() для преобразования объекта в массив массивов свойств, пар значений. Почему вы не включили фактический объект, используемый в коде в вопросе?
Показать ещё 1 комментарий
1

Если ваши данные изменений являются object of objects, вы можете использовать Object.values для циклического значения данных и слияния одинаковых идентификационных данных с помощью Object.assign

let data = [
  {
    name: 'Peter',
    age: 26,
    sID: 546589995544
  },
  {
    name: 'John',
    age: 33,
    sID: 554589525469
  }
];

let changes = {
    0:
  {
    age: 34,
    sID: 554589525469
  }
};

data.filter((idx,i)=>
    Object.values(changes).forEach((index)=>
        (index.sID == idx.sID) ? Object.assign(data[i],index) : null
        )
);
console.log(data);
  • 0
    Спасибо за Ваш ответ. Работает до сих пор. Можете ли вы объяснить мне, как это будет работать, если бы у меня был объект с ключами для каждого объекта, а не просто новое поле с уникальным идентификатором?
  • 0
    Я думаю, что вы можете использовать Object.keys , это будет получать ключи объекта в виде списка массивов ..
1

Используя lodash, вы можете выполнить это с помощью unionBy:

const newData = _.unionBy(changes, data, 'sID'); // values from changes will be picked

Это позволит выбрать объекты из массивов на основе sID и объединить их в один массив.

  • 0
    Работает, пока новый объект не будет добавлен к начальным данным.
  • 0
    @SVARTBERG, когда добавляется новый объект, снова запустите unionBy.
1

Вы можете использовать sId Map для быстрого поиска:

const byId = new Map( data.map( el => [el.sID, el]));

Тогда для каждого изменения мы можем найти, если obj уже существует, если не добавить его, если да, мы мутируем:

changes.forEach(change => {
 const res = byId.get( change.sID );
 if( res ){
   Object.assign( res, change);
 }else{
   data.push(change);
   byId.set( change.sID, change);
 }
});
  • 0
    Что такое данные в вашем случае? И вид той же проблемы, что и в комментарии к ответу guest271314
  • 0
    @svartberg это основано на вашем коде.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню