Сравните значение двух больших массивов со значением в Node.js - PullRequest
1 голос
/ 03 апреля 2020

У меня есть два массива, один из которых содержит 200 000 объектов товаров из файла CSV, а другой содержит 200 000 объектов товаров из базы данных.

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

Мне нужно сравнить все 200 000 объектов CSV с 200 000 объектов базы данных. Если объект CSV уже существует в массиве объектов базы данных, я помещаю его в массив «update» вместе с идентификатором из совпадения, а если нет, то я помещаю его в «новый» массив.

По завершении я обновляю все «обновленные» объекты в базе данных и вставляю все «новые». Это происходит быстро (несколько секунд).

Однако этап сравнения занимает несколько часов. Мне нужно сравнить три значения: канал (строка), дата (дата) и время (строка). Если все три одинаковы, это совпадение. Если это не так, то это не совпадение.

Это код, который у меня есть:

  const newProducts = []; 
  const updateProducts = [];
  csvProducts.forEach((csvProduct) => {

    // check if there is a match
    const match = dbProducts.find((dbProduct) => {
      return dbProduct.channel === csvProduct.channel && moment(dbProduct.date).isSame(moment(csvProduct.date), 'day') && dbProduct.start_time === csvProduct.start_time;
    });

    if (match) {
      // we found a match, add it to updateProducts array
      updateProducts.push({
        id: match.id,
        ...csvProduct
      });

      // remove the match from the dbProducts array to speed things up
      _.pull(dbProducts, match);
    } else {
      // no match, it's a new product
      newProducts.push(csvProduct);
    }
  });

Я использую библиотеки lodash и moment.js.

Узкое место в проверке, если есть совпадают, есть идеи, как это ускорить?

1 Ответ

1 голос
/ 03 апреля 2020

Это задание для класса Map . Массивы доставляют массу хлопот, потому что их нужно искать линейно. Карты (и Наборы ) можно искать быстро. Вы хотите выполнить сопоставление в оперативной памяти, а не нажимать на свою базу данных для каждого отдельного объекта во входящем файле.

Итак, сначала прочитайте каждую запись в вашей базе данных и создайте карту, в которой ключами являются такие объекты, как этот {start_time, date, channel} и значения id. (Я ставлю время на первое место, потому что думаю, что это атрибут с самыми разными значениями. Это попытка ускорить поиск.)

Примерно такой псевдокод.

 const productsInDb = new Map()
 for (const entry in database) {
     const key = {  // make your keys EXACTLY the same when you load your Map ..
         start_time: entry.start_time,
         date: moment(entry.date), 
         entry.channel}
     productsInDb.add(key, entry.id)
 }

Это займет целый беспорядок оперативной памяти, ну и что? Это то, для чего нужна ОЗУ.

Затем выполните сопоставление более или менее так, как вы это делали в своем примере, но с использованием своей карты.

const newProducts = []; 
const updateProducts = [];
csvProducts.forEach((csvProduct) => {

  // check if there is a match
  const key = {     // ...and when you look up entries in the Map.
         start_time: entry.start_time,
         date: moment(entry.date), 
         entry.channel}
  const id = productsInDb.get(key)
  if (id) {
      // we found a match, add it to updateProducts array
      updateProducts.push({
         id: match.id,
        ...csvProduct
      });
      // don't bother to update your Map here 
      // unless you need to do something about dups in your csv file
  } else {
    // no match, it's a new product
    newProducts.push(csvProduct)
  }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...