Официальный @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.
- Большие данные передают потоками.
- Повтор вставки требует дедупликации.
Что почитать дальше
- ClickHouse fundamentals - MergeTree и колоночное хранение.
- Моделирование и запросы - схема аналитических событий.