【问题标题】:Update object in array from another object in array从数组中的另一个对象更新数组中的对象
【发布时间】:2019-04-19 07:07:23
【问题描述】:

在我的代码中,我有两个数组,第一个包含多个对象。而第二个是存储序列化的表单数据(映射到 JSON)。所以两个数组都有相同的键。

我想要实现的是根据新数组中对象的值动态更新原始数组中对象的值,通过对象中的ID。

在网上找到了一些示例,但很难让它们起作用。因为它们中的大多数都显示了任一级别的对象,但我正在处理数组中复杂的嵌套对象。

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'
        }
    }
]

【问题讨论】:

  • 为什么第一个对象中的size 没有改变。它应该已更改为 medium,因为在 newData 具有 id 1 的对象具有大小 medium
  • @MaheerAli 哦,是的,你是对的。现在更正了。感谢您指出。
  • 2 只有“Size: Small”而不是“Storage: Normal”的标准是什么?...而1 更新其属性。
  • @briosheje 抱歉,这纯粹是错误。 2 的输出也应该有 "Storage: Normal"。感谢您指出。
  • 好的。 Id 是唯一的吗?您可以通过该键引用项目以进行查找吗?

标签: javascript jquery arrays json object


【解决方案1】:

您可以将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; }

【讨论】:

  • 我尝试了您的解决方案,但似乎在更新嵌套属性时,它将更新的属性添加到根键而不是其自己的父键。并且包含实际密钥的父密钥保持不变。
  • 可能你的数据不一致。
【解决方案2】:

您可以创建一个组合嵌套对象的函数。然后使用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)

【讨论】:

    猜你喜欢
    • 2018-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 2021-12-09
    • 1970-01-01
    • 2021-03-30
    • 1970-01-01
    相关资源
    最近更新 更多