← назад к разделу

Официальный @clickhouse/client подключается к ClickHouse по HTTP и поддерживает потоковые форматы. Для аналитических событий удобен JSONEachRow: каждая строка - отдельный JSON-объект.

Вставка событий

import { createClient } from '@clickhouse/client';

const clickhouse = createClient({
  url: process.env.CLICKHOUSE_URL,
  username: process.env.CLICKHOUSE_USER,
  password: process.env.CLICKHOUSE_PASSWORD,
  database: 'analytics',
});

await clickhouse.insert({
  table: 'order_events',
  values: [{ order_id: 42, type: 'created', created_at: '2026-10-28 12:00:00' }],
  format: 'JSONEachRow',
});

Список полей и типы должны совпадать с таблицей. DateTime не является ISO-строкой автоматически: часовой пояс и формат выбирают по схеме и настройкам сервера.

Аналитический запрос

const result = await clickhouse.query({
  query: `
    SELECT type, count() AS total
    FROM order_events
    WHERE created_at >= {from:DateTime}
    GROUP BY type
    ORDER BY total DESC
  `,
  query_params: { from: '2026-10-01 00:00:00' },
  format: 'JSONEachRow',
});
const rows = await result.json();

Параметры передаются отдельно от текста запроса. Фильтр по created_at позволяет читать только нужные партиции и колонки, а не всю таблицу с агрегацией в Node.js.

Потоки и объем

Для большой вставки передают поток JSONEachRow, а не гигантский массив объектов. Для большого результата выбирают потоковое чтение, ограничение или агрегацию на стороне ClickHouse.

Ошибки вставки нельзя считать успешной записью по одному вызову insert: обрабатывают исключение и идемпотентность повтора. Повтор без ключа дедупликации может удвоить события, поэтому событие имеет стабильный ID и политику доставки.

Коротко

  • JSONEachRow передает по одному объекту на строку.
  • Параметры запроса не интерполируют вручную.
  • Агрегацию и фильтры выполняет ClickHouse, а не JavaScript.
  • Большие данные передают потоками.
  • Повтор вставки требует дедупликации.

Что почитать дальше