Обновить объект в массиве из другого объекта в массиве - PullRequest
2 голосов
/ 19 апреля 2019

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

Чего я хочу добиться, это динамически обновлять значения объекта в исходном массиве на основе значений объекта в новом массиве по идентификатору в объекте.

Нашел несколько примеров в интернете, но сложно заставить их работать. Потому что большинство из них показывает один уровень объектов, но я работаю над сложными вложенными объектами в массиве.

var products = [
    {
        Id: 1,
        Name: 'Product1',
        Attributes: {
            Storage: 'Normal',
            Size: 'Small'
        }
    },
    {
        Id: 2,
        Name: 'Product2',
        Attributes: {
            Storage: 'Normal',
            Size: 'Small'
        }
    }
];

var newData = [
    {
        Id: 2,
        Name: 'French Fries'
    },
    {
        Id: 1,
        Attributes: {
            Size: 'Medium'
        }
    }
];

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

Output:
[
    {
        Id: 1,
        Name: 'Product1',
        Attributes: {
            Storage: 'Normal',
            Size: 'Medium'
        }
    },
    {
        Id: 2,
        Name: 'French Fries',
        Attributes: {
            Storage: 'Normal',
            Size: 'Small'
        }
    }
]

Ответы [ 2 ]

3 голосов
/ 19 апреля 2019

Вы можете взять Map для элементов обновления и повторить products.

Если элемент найден для обновления, используйте рекурсивный подход, итерируйте записи и проверьте, является ли значение объектом, а затем итерируйте вложенные свойства.

Если вложенный объект не найден, обновите свойство.

Это работает и для массивов.

function update(target, source) {
    Object.entries(source).forEach(([key, value]) => {
        if (value && typeof value === 'object') {
            update(target[key] = target[key] || (Array.isArray(value) ? [] : {}), value);
        } else if (target[key] !== value) {
            target[key] = value;
        }
    });
}

var products = [{ Id: 1, Name: 'Product1', Attributes: { Storage: 'Normal', Size: 'Small' } }, { Id: 2, Name: 'Product2', Attributes: { Storage: 'Normal', Size: 'Small' } }],
    newData = [{ Id: 2, Name: 'French Fries' }, { Id: 1, Attributes: { Size: 'Medium' } }],
    map = new Map(newData.map(o => [o.Id, o]));

products.forEach(o => map.has(o.Id) && update(o, map.get(o.Id)));

console.log(products);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 19 апреля 2019

Вы можете создать функцию, которая объединяет вложенные объекты.А затем используйте map() и find() для создания объединенного массива объектов.

var products = [
    {
        Id: 1,
        Name: 'Product1',
        Attributes: {
            Storage: 'Normal',
            Size: 'Small'
        }
    },
    {
        Id: 2,
        Name: 'Product2',
        Attributes: {
            Storage: 'Normal',
            Size: 'Small'
        }
    }
];

var newData = [
    {
        Id: 2,
        Name: 'French Fries'
    },
    {
        Id: 1,
        Attributes: {
            Size: 'Medium'
        }
    }
];

const haveNested = obj => Object.values(obj).some(x => typeof x === "object");

function combine(obj1,obj2){

  if(!haveNested(obj1)) return ({...obj1,...obj2})
  let res = obj1
  for(let key in obj1){
    if(typeof obj1[key] === "object"){
      res[key] = combine(obj1[key],obj2[key]);
    }
    else if(obj2[key]) res[key] = obj2[key]
  }
  return res;
}

const result = products.map(x => {
  let temp = newData.find(a => a.Id === x.Id);
  return temp ? combine(x,temp) : x;
})

console.log(result)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...