Javascript 通过匹配ID更新嵌套对象

Javascript 通过匹配ID更新嵌套对象,javascript,arrays,object,data-structures,Javascript,Arrays,Object,Data Structures,我有一个包含嵌套对象的数组,如果它们匹配,我需要从另一个对象数组更新该数组 以下是我要更新的数据结构: const invoices = { BatchItemRequest: [ { bId: "bid10", Invoice: { Line: [ { SalesItemLineDetail: { ItemAccountRef: { AccountCode: "10110" }, }, },

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

以下是我要更新的数据结构:

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" },
];
我想使用accounts更新发票,如果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;
  })
);
});
这种方法存在问题(我认为它不起作用,因为我需要做另一个嵌套映射),但它也创建了一个新数组,只包括发票的嵌套元素


有人知道一个很好的方法吗?

这不是最干净的代码,但它完成了任务:

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或spread运算符。

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

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或spread运算符。

首先,最好从帐户数组创建映射。我们将使用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的递归克隆。首先,最好从accounts数组创建映射。我们将使用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之类的东西创建If的递归克隆。cloneDeep

您的
帐户
数组必须是这样吗?作为帐户代码到
Id
值的映射,使用它会容易得多您的
帐户
数组必须是这样的吗?作为帐户代码到
Id
values的映射,使用它会容易得多谢谢!非常好,谢谢!非常好,谢谢!很好,谢谢!效果很好