Обновлен вложенный объект по совпадению ID - PullRequest
0 голосов
/ 01 мая 2020

У меня есть массив с вложенными объектами, которые мне нужно обновить из другого массива объектов, если они совпадают.

Вот структура данных, которую я хочу обновить:

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" },
];

Я хочу обновить счета, используя учетные записи, вставив Id, если AccountCode совпадает, чтобы получить следующую структуру:

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;
  })
);
});

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

Кто-нибудь знает хороший подход к этому?

Ответы [ 2 ]

1 голос
/ 01 мая 2020

Сначала будет хорошо создать карту из массива ваших учетных записей. Мы будем go один раз для массива с O (n), а затем будем читать идентификаторы по коду с O (1). И вложенным форсом является 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]))

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

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

Если вам не нужно мутировать исходные "счета-фактуры" больших объектов и все вложенные объекты, то вы можете создать рекурсивный клон, если с что-то вроде loda sh .cloneDeep

1 голос
/ 01 мая 2020

Это не самый чистый код, но он выполняет свою работу:

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 или оператор распространения.

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