Node.js SQL Server: Поток

В этом уроке вы узнаете, как использовать поток для более эффективной обработки больших наборов результатов.

Это руководство начинается с того места, где закончилось руководство Вызов хранимой процедуры с параметром OUTPUT в Node.js.

Как использовать поток Node.js для обработки больших наборов результатов

Поток позволяет эффективно обрабатывать большой набор результатов, обрабатывая его построчно, а не загружая его в память сразу.

Поток полезен при обработке больших наборов результатов из SQL Server без использования большого объема памяти сервера.

Ниже описаны шаги по использованию потока:

Сначала подключитесь к SQL Server :

const pool = await sql.connect(config);

Во-вторых, создайте объект Request, который представляет запрос, выполняемый к SQL Server, и включает потоковую передачу:

const request = new sql.Request(pool);
request.stream = true;

В-третьих, обрабатывайте данные по мере их поступления. Для этого используется метод on() объекта Request. Метод request.on() обрабатывает различные события, которые происходят во время выполнения запроса, когда поток включен:

  • набор записей: срабатывает, когда доступны метаданные столбцов.
  • строка: срабатывает для каждой строки в наборе результатов.
  • ошибка: срабатывает при возникновении ошибки.
  • done: срабатывает после завершения выполнения запроса.

Например, ниже показано, как обрабатывать каждую строку данных по мере их поступления с помощью request.on() с событием строки:

request.on('row', row => {
  console.log('Row:', row);
});

Пример потоковой передачи данных в файл CSV

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

Шаг 1. Создайте новый файл с именем stream.js в каталоге проекта.

Шаг 2. Определите функцию exportAuthorsToCSV, которая экспортирует все строки из таблицы Authors в CSV-файл:

import fs from 'fs';
import sql from 'mssql';
import { config } from './config.js';
const exportAuthorsToCSV = async(csvFilename) => {
  try {
    // Create a write stream for the CSV file
    const writeStream = fs.createWriteStream(csvFilename);
    // Connect to the database
    const pool = await sql.connect(config);
    // Create a new request with streaming enabled
    const request = new sql.Request(pool);
    request.stream = true;
    // Execute the query
    request.query('SELECT * FROM Authors ORDER BY FirstName');
    // Event handlers for the streaming
    request.on('recordset',(columns) => {
      let header = '';
      for(const column in columns) {
        header += `${column},`;
      }
      // remove the last comma(,)
      header = header.slice(0, -1);
      // write the header
      writeStream.write(header + '\n');
    });
    // Process each row when it is arrived
    request.on('row',({ AuthorID, FirstName, LastName, BirthDate }) => {
      const csvRow = `${AuthorID},${FirstName},${LastName},${BirthDate.toLocaleDateString()}`;
      writeStream.write(csvRow + '\n');
    });
    // Error handlers for the request
    request.on('error',(err) => {
      console.error('Error:', err);
      writeStream.end();
    });
    // Event handler for when the query is done
    request.on('done',(result) => {
      console.log('Query done. Rows affected:', result.rowsAffected);
      writeStream.end();
    });
  } catch(err) {
    console.error(err);
  }
};
export { exportAuthorsToCSV };

Как это работает.

Сначала импортируйте объекты fs, sql и config из модулей fs, mssql и config.js соответственно.

import fs from 'fs';
import sql from 'mssql';
import { config } from './config.js';

Во-вторых, определите функцию exportAuthorsToCSV, которая принимает имя файла CSV:

const exportAuthorsToCSV = async(csvFilename) => {
    //...
};

В-третьих, создайте поток записи для CSV-файла:

const writeStream = fs.createWriteStream(csvFilename);

В-четвертых, подключитесь к SQL Server, используя предоставленный объект конфигурации.

const pool = await sql.connect(config);

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

В-пятых, создайте новый запрос с включенной потоковой передачей:

const request = new sql.Request(pool);
request.stream = true;

В-шестых, выполните запрос, который извлекает данные из таблицы Authors:

request.query('SELECT * FROM Authors ORDER BY FirstName');

В-седьмых, запишите заголовок CSV-файла один раз в обработчике событий набора записей:

request.on('recordset',(columns) => {
  let header = '';
  for(const column in columns) {
    header += `${column},`;
  }
  // remove the last comma(,)
  header = header.slice(0, -1);
  // write the header
  writeStream.write(header + '\n');
});

Как это работает.

  1. Инициализируйте заголовок пустой строкой.
  2. Выполните итерацию по свойствам объекта columns с помощью цикла for…in и объедините имена свойств(AuthorID, FirstName, LastName и BirthDate) в одну строку. Обратите внимание, что объект columns содержит все поля в таблице Authors, включая AuthorID, FirstName, LastName и BirthDate.
  3. Удалите последнюю запятую(,) из строки заголовка с помощью метода slice().
  4. Запишите заголовок в CSV-файл, вызвав метод write() объекта writeStream.

Восьмое, записывайте каждую строку в CSV-файл, когда она поступает в обработчик событий строки:

request.on('row',({ AuthorID, FirstName, LastName, BirthDate }) => {
  const csvRow = `${AuthorID},${FirstName},${LastName},${BirthDate.toLocaleDateString()}`;
  writeStream.write(csvRow + '\n');
});

Девятое, если произошла ошибка, выведите ее на консоль и завершите поток в обработчике событий ошибки:

request.on('error',(err) => {
  console.error('Error:', err);
  writeStream.end();
});

В-десятых, выведите сообщение на консоль и завершите поток в обработчике событий done:

request.on('done',(result) => {
  console.log('Query done. Rows affected:', result.rowsAffected);
  writeStream.end();
});

Одиннадцатое, выведите сообщение об ошибке на консоль в блоке catch:

console.error(err);

Наконец, экспортируйте функцию exportAuthorsToCSV.

Шаг 3. Измените index.js для использования функции exportAuthorsToCSV:

import { exportAuthorsToCSV } from './stream.js';
exportAuthorsToCSV('data/output.csv');

Как это работает.

Сначала импортируйте функцию exportAuthorsToCSV из модуля stream.js.

import { exportAuthorsToCSV } from './stream.js';

Во-вторых, вызовите функцию exportAuthorsToCSV() для экспорта данных об авторе в CSV-файл, расположенный по адресу data/output.csv:

exportAuthorsToCSV('data/output.csv');

Шаг 4. Откройте терминал и выполните следующую команду для запуска файла index.js:

npm start

Если программа отработает успешно, вы увидите новый выходной файл output.csv в каталоге данных:

AuthorID,FirstName,LastName,BirthDate
2,Agatha,Christie,9/15/1890
9,Charles,Dickens,2/7/1812
22,Emily,Bronte,7/30/1818
...

Краткое содержание

  • Используйте поток для эффективной обработки больших наборов результатов.
  • Установите свойство stream объекта Request на true, чтобы включить потоковую передачу.
  • Используйте метод request.on() для обработки событий, возникающих во время выполнения запроса после включения потоковой передачи.
Мирослав С.

Автор статей, ИБ-специалист