Как разработчик JavaScript, работа с файлами CSV или TSV может быть чрезвычайно громоздкой. Но что, если бы существовал более быстрый способ? Знаете ли вы, что PostgreSQL поддерживает потоковую передачу данных непосредственно в таблицу и из нее?

JSONL, да? Что?

Когда вы сталкиваетесь с задачей импорта больших объемов данных, вариантами по умолчанию обычно являются файлы .csv или .tsv (или .xlsx, если вы чувствуете себя более предприимчивым!). Как разработчики JavaScript, мы чувствуем себя комфортно, работая с JSON и объектами. Но слышали ли вы о JSONL?

Что такое JSONL?

JSONL — это просто версия объектов JSON, разделенных строками. Каждая строка в файле JSONL представляет собой отдельный объект JSON, что упрощает анализ и обработку данных. Это делает его идеальным форматом для данных, которые необходимо обрабатывать в режиме реального времени или в потоковом режиме.

В приведенном ниже примере у нас есть простое экспресс-приложение, которое мы хотим разрешить пользователю импортировать контакты из CRM.

Каждый контакт будет представлен в таком объекте.

{ 
  "first_name": "Bob", 
  "last_name: "Doe", 
  "email": "[email protected]", 
  "phone": "+14155555555"
}

Чтобы создать файл JSONL, было бы просто выглядеть так.

{ "first_name": "Bob", "last_name": "Doe", "email": "[email protected]", "phone": "+14155555555"}
{ "first_name": "Jan", "last_name": "Doe", "email": "[email protected]", "phone": "+14155555556"}
{ "first_name": "Jon", "last_name": "Doe", "email": "[email protected]", "phone": "+14155555557"}

Где каждая новая строка представляет собой объект JSON с представлением каждого контакта.

На практике.
Мы собираемся создать простое веб-приложение, которое будет передавать эти данные напрямую в Postgres.

Шаг 1. Создайте базу данных PostgreSQL

CREATE DATABASE my_data;

Шаг 2. Создайте таблицу базы данных PostgreSQL с названием contact

CREATE TABLE contacts (
  first_name VARCHAR(255),
  last_name VARCHAR(255),
  email VARCHAR(255),
  phone VARCHAR(255)
);

Шаг 3. Настройте среду Node.js

Прежде чем вы сможете начать работать с JSONL, вам необходимо настроить среду Node.js. Для этого вам необходимо установить Node.js и NPM (диспетчер пакетов Node) на свой компьютер. Вы можете скачать Node.js с официального сайта Node.js.

npm init 

затем установите необходимые пакеты

npm i express 
npm i pg // for connecting to postgres
npm i pg-copy-streams // for working with streams

Шаг 4. Создайте экспресс-приложение, которое будет принимать массовые данные

const express = require('express');
const { Pool } = require('pg');
const { copyFrom } = require('pg-copy-streams');
const app = express();

// create a pool of Postgres connections
// this example is connecting to a local postgres database. This should be adjusted to fit your needs.
const pool = new Pool({
  connectionString: "postgres://username:password@localhost:5432/mydatabase",
  ssl: true
});

// handle POST requests to bulk import data into the contacts table
app.post('/contacts', async (req, res) => {
  const data = req.body; // assuming the request body contains JSONL data
  const client = await pool.connect();

  try {
    // split the JSONL data into separate lines and parse each line as JSON
    const lines = data.split('\n');
    const values = lines.map(line => JSON.parse(line));
    
    // use a transaction to perform the bulk import
    await client.query('BEGIN');
    const query = 'COPY contacts (first_name, last_name, email, phone) FROM STDIN (FORMAT JSON)';
    const copyStream = client.query(copyFrom(query));
    values.forEach(row => copyStream.write(JSON.stringify(row) + '\n'));
    copyStream.end();
    await client.query('COMMIT');
    
    // send a response to the client
    res.sendStatus(201);
  } catch (err) {
    console.error(err);
    await client.query('ROLLBACK');
    res.sendStatus(500);
  } finally {
    client.release();
  }
});

app.listen(3000, () => console.log('App listening on port 3000'));

Шаг 5. Перейдите к своему любимому HTTP-клиенту (Postman, Thunder Client)
Создайте запрос POST к http://localhost:3000/contacts с необработанным телом данных JSON.

{ "first_name": "Bob", "last_name": "Doe", "email": "[email protected]", "phone": "+14155555555"}
{ "first_name": "Jan", "last_name": "Doe", "email": "[email protected]", "phone": "+14155555556"}
{ "first_name": "Jon", "last_name": "Doe", "email": "[email protected]", "phone": "+14155555557"}

И ПОСТ!

Такой подход снова сделал работу с Bulk Inserts быстрой и увлекательной! Попробуйте это в своем следующем проекте!