Node.js 原生接口

Node.js 原生 API 支持通过 TableSessionPool 与 IoTDB 表模型进行交互,可执行表模型下的数据写入、查询、非查询 SQL 以及连接管理等操作。TableSessionPool 在连接池能力基础上增加了数据库上下文管理,适合在 Node.js 应用中访问关系型表结构的数据。

本文将围绕 TableSessionPool 的使用进行说明,涵盖从环境准备、核心操作步骤到常用接口的完整内容。

1. 环境准备

1.1 前置依赖

  • Node.js >= 14.0.0
  • npm >= 6.0.0
  • IoTDB >= 2.0.11

1.2 安装方法

  • 方式一:通过 npm 直接安装(推荐)

在 Node.js 项目中执行:

npm install @iotdb/client
  • 方式二:从源码构建

如需使用仓库中的开发版本,可克隆源码并安装依赖:

git clone https://github.com/apache/iotdb-client-nodejs.git
cd iotdb-client-nodejs
git checkout develop
npm ci

Linux、macOS 或 WSL 环境执行:

npm run build

Windows PowerShell 环境执行:

npm run build:esbuild
npm run build:types
New-Item -ItemType Directory -Force -Path dist\thrift\generated
Copy-Item src\thrift\generated\*.js,src\thrift\generated\*.d.ts -Destination dist\thrift\generated -Force

构建完成后,可在业务项目中通过客户端源码目录的绝对路径进行本地安装:

npm install /absolute/path/to/iotdb-client-nodejs

如使用 TypeScript,无需额外安装类型声明,客户端已内置完整的 TypeScript 类型定义。

注意:请勿使用高版本客户端连接低版本服务。

2. 核心步骤

使用 Node.js 原生接口操作 IoTDB 表模型的三个核心步骤如下:

  1. 创建连接池实例:初始化一个 TableSessionPool 对象,配置连接参数、数据库和池大小。
  2. 执行数据库操作:直接通过连接池执行表创建、数据写入或查询等操作。
  3. 关闭连接池资源:程序结束时调用 tablePool.close(),释放所有连接。

下面的章节用于说明开发的核心流程,并未演示所有参数和接口。如需了解完整能力,可查阅 @iotdb/client 源码及示例。

2.1 创建连接池实例

2.1.1 单节点连接

import { TableSessionPool } from '@iotdb/client';

const tablePool = new TableSessionPool('localhost', 6667, {
  username: 'root',
  password: 'root',
  database: 'test',
  maxPoolSize: 10,
  minPoolSize: 2,
});

await tablePool.init();

其中 database 用于设置表模型的默认数据库。配置后,连接池执行查询和写入时会使用该数据库上下文。

2.1.2 多节点连接

在集群环境下,推荐使用 nodeUrls 配置多个节点。连接池会以轮询方式在多个节点间分配连接,并在连接失败时尝试其他可用节点。

import { TableSessionPool } from '@iotdb/client';

const tablePool = new TableSessionPool({
  nodeUrls: [
    '192.168.1.100:6667',
    '192.168.1.101:6667',
    '192.168.1.102:6667',
  ],
  username: 'root',
  password: 'root',
  database: 'test',
  maxPoolSize: 10,
  minPoolSize: 2,
});

await tablePool.init();

连接池参数可按业务并发量调整:minPoolSize 建议设置为平均并发负载,maxPoolSize 建议设置为峰值并发负载并预留 20% 到 30% 缓冲;maxIdleTime 用于清理长期空闲连接,waitTimeout 用于控制连接池耗尽时的最大等待时间。生产环境建议监控 getPoolSize()、getAvailableSize() 和 getInUseSize(),根据峰值负载调整连接池大小。

2.1.3 SSL/TLS 连接

如 IoTDB 服务端启用了 SSL/TLS,可在创建连接池时开启 SSL,并指定证书相关参数。

import { TableSessionPool } from '@iotdb/client';
import * as fs from 'fs';

const tablePool = new TableSessionPool({
  host: 'localhost',
  port: 6667,
  username: 'root',
  password: 'root',
  database: 'test',
  enableSSL: true,
  sslOptions: {
    ca: fs.readFileSync('/path/to/ca.crt'),
    cert: fs.readFileSync('/path/to/client.crt'),
    key: fs.readFileSync('/path/to/client.key'),
    rejectUnauthorized: true,
  },
});

await tablePool.init();

2.1.4 写入重定向

在多节点 IoTDB 集群中,客户端支持写入重定向。写入操作发送到非目标节点时,服务端可能返回重定向建议,客户端会缓存目标路由,并在后续写入时优先使用更合适的节点。

import { TableSessionPool } from '@iotdb/client';

const tablePool = new TableSessionPool({
  nodeUrls: [
    '192.168.1.100:6667',
    '192.168.1.101:6667',
    '192.168.1.102:6667',
  ],
  username: 'root',
  password: 'root',
  database: 'test',
  maxPoolSize: 10,
  enableRedirection: true,
  redirectCacheTTL: 300000,
});

await tablePool.init();

启用重定向后,可减少跨节点转发,提升写入吞吐并降低网络延迟。

2.2 数据库操作

2.2.1 创建数据库和表

await tablePool.executeNonQueryStatement('CREATE DATABASE IF NOT EXISTS test');

await tablePool.executeNonQueryStatement('USE test');

await tablePool.executeNonQueryStatement(`
  CREATE TABLE IF NOT EXISTS device_metrics (
    time TIMESTAMP TIME,
    device_id STRING TAG,
    region STRING ATTRIBUTE,
    temperature FLOAT FIELD,
    humidity FLOAT FIELD
  )
`);

2.2.2 写入 Tablet 数据

表模型写入时,需要指定表名、列名、数据类型、时间戳和值。以下示例按列组织 values,每个数组对应一个非时间列。

import { ColumnCategory, TSDataType } from '@iotdb/client';

await tablePool.insertTablet({
  tableName: 'device_metrics',
  columnNames: ['device_id', 'region', 'temperature', 'humidity'],
  columnTypes: [
    TSDataType.STRING,
    TSDataType.STRING,
    TSDataType.FLOAT,
    TSDataType.FLOAT,
  ],
  columnCategories: [
    ColumnCategory.TAG,
    ColumnCategory.ATTRIBUTE,
    ColumnCategory.FIELD,
    ColumnCategory.FIELD,
  ],
  timestamps: [Date.now(), Date.now() + 1000],
  values: [
    ['device_1', 'beijing', 25.5, 60.0],
    ['device_1', 'beijing', 26.0, 61.5],
  ],
});

如项目中未直接使用枚举,columnTypes 也可以使用数据类型编码。

写入数据时建议优先使用 insertTablet 批量写入,减少网络往返次数;常见批量大小可从 100 到 1000 行开始压测,再根据数据规模、网络和服务端资源调整。

2.2.3 查询数据

查询结果通过 SessionDataSet 返回。使用完成后应调用 close() 释放服务端查询资源。

const dataSet = await tablePool.executeQueryStatement(`
  SELECT time, device_id, region, temperature, humidity
  FROM device_metrics
  WHERE device_id = 'device_1'
`);

while (await dataSet.hasNext()) {
  const row = dataSet.next();
  console.log(row.getFields());
}

await dataSet.close();

对于小型结果集,也可以使用 toArray() 将全部结果加载到内存:

const dataSet = await tablePool.executeQueryStatement('SHOW TABLES');
const rows = await dataSet.toArray();
console.log(rows);
await dataSet.close();

2.3 关闭连接池

await tablePool.close();

建议在应用退出、定时任务结束或服务销毁时统一关闭连接池,避免连接泄漏。

3. 常用接口

3.1 TableSessionPool

3.1.1 功能描述

TableSessionPool 是表模型推荐使用的连接池接口,支持自动会话管理和数据库上下文管理。调用查询、写入或非查询方法时,连接池会自动获取可用会话,执行完成后回收连接。

3.1.2 构造方式

构造方式说明
new TableSessionPool(host, port, config)传统构造方式,适用于单节点连接
new TableSessionPool(config)使用配置对象构造,适合 nodeUrls 多节点配置
new TableSessionPool(new PoolConfigBuilder().build())使用构建器模式构造,推荐用于参数较多的场景

3.1.3 方法列表

方法名描述
init()初始化连接池
close()关闭连接池并释放所有连接
executeQueryStatement(sql, timeoutMs?)执行查询 SQL,可设置查询超时时间
executeNonQueryStatement(sql)执行非查询 SQL,例如 DDL 或 DML
insertTablet(tablet)插入表模型 Tablet 数据
getPoolSize()获取当前连接池大小
getAvailableSize()获取当前可用连接数
getInUseSize()获取当前正在使用的连接数

3.1.4 配置项

配置项描述
host设置主机地址
port设置端口
nodeUrls设置多个节点地址,格式为 host:port
username设置用户名
password设置密码
database设置默认数据库
timezone设置时区
fetchSize设置查询结果批量拉取大小
maxPoolSize设置最大连接数
minPoolSize设置最小连接数
maxIdleTime设置最大空闲时间,单位为毫秒
waitTimeout设置获取连接的等待超时时间,单位为毫秒
enableSSL是否启用 SSL
sslOptions设置 SSL 参数
enableRedirection是否启用写入重定向
redirectCacheTTL设置重定向缓存过期时间,单位为毫秒

3.2 Tablet 参数

表模型 insertTablet 的常用参数如下:

参数描述
tableName目标表名
columnNames非时间列名称列表
dataTypes非时间列的数据类型列表
columnCategories非时间列的类别列表
timestamps时间戳列表
values列值列表,按列组织

columnNames、columnTypes、columnCategories 和 values 的顺序需要保持一致。

4. 数据类型

插入 Tablet 数据时,需要为每个列指定对应的数据类型。Node.js 客户端支持的常用类型如下:

类型编码类型名称JavaScript 类型说明
0BOOLEANboolean布尔值
1INT32number32 位整数
2INT64bigint64 位整数
3FLOATnumber32 位浮点数
4DOUBLEnumber64 位浮点数
5TEXTstringUTF-8 文本
8TIMESTAMPDate毫秒精度时间戳
9DATEDate日期类型
10BLOBBuffer二进制数据
11STRINGstringUTF-8 字符串

处理 INT64 类型时,建议在 JavaScript 中使用 bigint,避免超出 number 安全整数范围后出现精度损失。

5. 常见问题

  1. 默认数据库不存在:如果配置的 database 在连接池初始化时尚不存在,请先执行 CREATE DATABASE,随后显式执行 USE database_name,再创建表、查询或写入;也可以在初始化 TableSessionPool 之前预先创建数据库。

  2. 列不匹配:如果写入时出现列数量或类型不匹配,请检查 columnNames、columnTypes、columnCategories 和 values 的顺序及长度是否一致,并确认 values 按行组织且表结构与写入数据匹配。

  3. 查询结果占用内存过高:大结果集查询建议使用 hasNext() 和 next() 分批读取,并调小 fetchSize。仅在结果集较小时使用 toArray()。

  4. 获取连接超时:如果出现等待可用连接超时,通常说明连接池已被占满。可适当增大 waitTimeout 或 maxPoolSize,同时检查是否存在长时间未关闭的查询结果集。