【问题标题】:Updated nested object by matching ID通过匹配 ID 更新嵌套对象
【发布时间】:2020-04-30 22:46:41
【问题描述】:

我有一个包含嵌套对象的数组,如果它们匹配,我需要从另一个对象数组更新它。

这是我要更新的数据结构:

const invoices = {
 BatchItemRequest: [
 {
  bId: "bid10",
  Invoice: {
    Line: [
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "10110" },
        },
      },
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "11110" },
        },
        Amount: 2499,
      },
    ],
  },
},
{
  bId: "bid10",
  Invoice: {
    Line: [
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "10110" },
        },
      },
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "10111" },
        },
        Amount: 2499,
      },
    ],
  },
},
],
};

这是我要更新的对象数组:

const accounts = [
 { AccountCode: "10110", Id: "84" },
 { AccountCode: "11110", Id: "5" },
 { AccountCode: "10111", Id: "81" },
];

我想使用帐户更新发票,如果 AccountCode 匹配,则插入 Id,以获得以下结构:

const invoices = {
 BatchItemRequest: [
 {
  bId: "bid10",
  Invoice: {
    Line: [
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "10110", Id: "84" },
        },
      },
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "11110", Id: "5" },
        },
        Amount: 2499,
      },
    ],
  },
},
{
  bId: "bid10",
  Invoice: {
    Line: [
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "10110", Id: "84" },
        },
      },
      {
        SalesItemLineDetail: {
          ItemAccountRef: { AccountCode: "10111", Id: "81" },
        },
        Amount: 2499,
      },
    ],
  },
},
],
};

我尝试了各种方法,例如:

const mapped = invoices.BatchItemRequest.map((item1) => {
return Object.assign(
  item1,
  accounts.find((item2) => {
    return item2 && item1.Invoice.Line.ItemAccountRef.AccountCode === item2.AccountCode;
  })
);
});

这种方法存在问题(它不起作用,因为我认为我需要做另一个嵌套映射),但它也会创建一个新数组,仅包含发票的嵌套元素。

有没有人知道解决这个问题的好方法?

【问题讨论】:

  • 你的accounts 数组看起来像这样吗?将帐户代码映射到Id 值会更容易

标签: javascript arrays object data-structures


【解决方案1】:

这不是最干净的代码,但它可以完成工作:

function matchInvoiceWithAccount(invoices, accounts) {
    const mappedInvoices = invoices.BatchItemRequest.map((request) => {
        // Shouldn't modify input parameter, could use Object.assign to create a copy and modify the copy instead for purity
        request.Invoice.Line = request.Invoice.Line.map((line) => {
            const accountCode = line.SalesItemLineDetail.ItemAccountRef.AccountCode;
            // If accounts was a map of AccountCode to Id you would't need to search for it which would be more effective
            const account = accounts.find((account) => account.AccountCode === accountCode);

            if (account) {
                line.SalesItemLineDetail.ItemAccountRef.Id = account.Id;
            }

            return line;
        });

        return request;
    });

    return {
        BatchItemRequest: mappedInvoices,
    };
}

您可以并且可能应该做的是不修改函数的输入参数,但这需要您以更好的方式复制原始参数,使用 Object.assign 或扩展运算符。

【讨论】:

  • 谢谢!完美运行。
【解决方案2】:

首先,最好从您的帐户数组中创建 Map。我们将使用 O(n) 进行一次数组,然后使用 O(1) 通过代码读取 id。并且嵌套fors是O(m*n),在大数组中会慢很多。

const idsByAccountCodes = new Map();
accounts.forEach((data) => {
    idsByAccountCodes.set(data.AccountCode, data.Id);
})

或更短:

const idsByAccountCode = new Map(accounts.map((data) => [data.AccountCode, data.Id]))

如果你想改变原始值,你可以遍历所有嵌套级别并添加值

for ( const {Invoice:{ Line: line }} of invoices.BatchItemRequest){
    for ( const {SalesItemLineDetail: {ItemAccountRef: item}} of line){
      item.Id = idsByAccountCodes.get(item.AccountCode) || 'some default value'
      // also if you don't have ids for all codes you need to define logic for  that case
    }
}

如果您不需要改变原始大对象“发票”和所有嵌套对象,那么您可以使用 lodash.cloneDeep 之类的东西创建 if 的递归克隆

【讨论】:

  • 谢谢!效果很好
猜你喜欢
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多