diff --git a/src/.vuepress/sidebar/V2.0.x/en-Table.ts b/src/.vuepress/sidebar/V2.0.x/en-Table.ts index 73eee9bcd..52cf384b3 100644 --- a/src/.vuepress/sidebar/V2.0.x/en-Table.ts +++ b/src/.vuepress/sidebar/V2.0.x/en-Table.ts @@ -184,6 +184,7 @@ export const enSidebar = { { text: 'C++ Native API', link: 'Programming-Cpp-Native-API_apache' }, { text: 'GO Native API', link: 'Programming-Go-Native-API_apache' }, { text: 'C# Native API', link: 'Programming-CSharp-Native-API_apache' }, + { text: 'Node.js Native API', link: 'Programming-NodeJS-Native-API_apache' }, { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT Protocol', link: 'Programming-MQTT_apache' }, { text: 'RESTAPI V1 ', link: 'RestAPI-V1_apache' }, diff --git a/src/.vuepress/sidebar/V2.0.x/en-Tree.ts b/src/.vuepress/sidebar/V2.0.x/en-Tree.ts index 5a25ed6b6..d73024d2d 100644 --- a/src/.vuepress/sidebar/V2.0.x/en-Tree.ts +++ b/src/.vuepress/sidebar/V2.0.x/en-Tree.ts @@ -189,7 +189,7 @@ export const enSidebar = { { text: 'C++ Native API', link: 'Programming-Cpp-Native-API' }, { text: 'Go Native API', link: 'Programming-Go-Native-API' }, { text: 'C# Native API', link: 'Programming-CSharp-Native-API' }, - { text: 'Node.js Native API', link: 'Programming-NodeJS-Native-API' }, + { text: 'Node.js Native API', link: 'Programming-NodeJS-Native-API_apache' }, { text: 'Rust Native API', link: 'Programming-Rust-Native-API' }, { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT Protocol', link: 'Programming-MQTT_apache' }, diff --git a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts index a1f69708b..20659a345 100644 --- a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts +++ b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts @@ -184,6 +184,7 @@ export const zhSidebar = { { text: 'C++原生接口', link: 'Programming-Cpp-Native-API_apache' }, { text: 'GO原生接口', link: 'Programming-Go-Native-API_apache' }, { text: 'C#原生接口', link: 'Programming-CSharp-Native-API_apache' }, + { text: 'Node.js原生接口', link: 'Programming-NodeJS-Native-API_apache' }, { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT协议', link: 'Programming-MQTT_apache' }, { text: 'RESTAPI V1 ', link: 'RestServiceV1_apache' }, diff --git a/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts b/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts index 0d1806cda..012afb49f 100644 --- a/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts +++ b/src/.vuepress/sidebar/V2.0.x/zh-Tree.ts @@ -183,7 +183,7 @@ export const zhSidebar = { { text: 'C++原生接口', link: 'Programming-Cpp-Native-API' }, { text: 'Go原生接口', link: 'Programming-Go-Native-API' }, { text: 'C#原生接口', link: 'Programming-CSharp-Native-API' }, - { text: 'Node.js原生接口', link: 'Programming-NodeJS-Native-API' }, + { text: 'Node.js原生接口', link: 'Programming-NodeJS-Native-API_apache' }, { text: 'Rust原生接口', link: 'Programming-Rust-Native-API' }, { text: 'JDBC', link: 'Programming-JDBC_apache' }, { text: 'MQTT协议', link: 'Programming-MQTT_apache' }, diff --git a/src/UserGuide/Master/Table/API/Programming-NodeJS-Native-API_apache.md b/src/UserGuide/Master/Table/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..811d0e9b7 --- /dev/null +++ b/src/UserGuide/Master/Table/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,371 @@ + + +# Node.js Native API + +The Node.js native API supports interacting with the IoTDB table model through `TableSessionPool`, enabling data insertion, queries, non-query SQL, and connection management under the table model. Building on connection pool capabilities, `TableSessionPool` adds database context management, making it suitable for accessing relational table data in Node.js applications. + +This document focuses on the usage of `TableSessionPool`, covering environment preparation, core steps, and common interfaces. + +## 1. Environment Preparation + +### 1.1 Prerequisites + +* Node.js >= 14.0.0 +* npm >= 6.0.0 +* IoTDB >= 2.0.11 + +### 1.2 Installation + +* **Option 1: Install directly via npm (recommended)** + +Run the following command in your Node.js project: + +```bash +npm install @iotdb/client +``` + +* **Option 2: Build from source** + +To use the development version from the repository, clone the source code and install dependencies: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +On Linux, macOS, or WSL, run: + +```bash +npm run build +``` + +On Windows PowerShell, run: + +```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 +``` + +After the build is complete, you can install the client locally in your business project via the absolute path of the client source directory: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +If you use TypeScript, no additional type declarations are required. The client comes with complete TypeScript type definitions built in. + +**Note: Do not use a higher-version client to connect to a lower-version server.** + +## 2. Core Steps + +The three core steps of operating the IoTDB table model with the Node.js native API are as follows: + +1. Create a connection pool instance: initialize a `TableSessionPool` object with connection parameters, database, and pool size. +2. Execute database operations: perform table creation, data insertion, or queries directly through the connection pool. +3. Close the connection pool: call `tablePool.close()` when the program ends to release all connections. + +The following sections describe the core development workflow and do not demonstrate all parameters and interfaces. For the complete capabilities, refer to the [`@iotdb/client` source code](https://github.com/apache/iotdb-client-nodejs/tree/develop/src) and [examples](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples). + +### 2.1 Creating a Connection Pool Instance + +#### 2.1.1 Single-Node Connection + +```typescript +import { TableSessionPool } from '@iotdb/client'; + +const tablePool = new TableSessionPool('localhost', 6667, { + username: 'root', + password: 'root', + database: 'test', + maxPoolSize: 10, + minPoolSize: 2, +}); + +await tablePool.init(); +``` + +Here `database` sets the default database for the table model. Once configured, the connection pool uses this database context for queries and writes. + +#### 2.1.2 Multi-Node Connection + +In a cluster environment, it is recommended to configure multiple nodes with `nodeUrls`. The connection pool distributes connections across nodes in a round-robin manner and tries other available nodes when a connection fails. + +```typescript +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(); +``` + +Connection pool parameters can be adjusted according to your workload: `minPoolSize` is recommended to be set to the average concurrent load, while `maxPoolSize` should be set to the peak concurrent load with a 20% to 30% buffer. `maxIdleTime` is used to clean up long-idle connections, and `waitTimeout` controls the maximum waiting time when the pool is exhausted. In production, it is recommended to monitor `getPoolSize()`, `getAvailableSize()`, and `getInUseSize()`, and adjust the pool size based on peak load. + +#### 2.1.3 SSL/TLS Connection + +If SSL/TLS is enabled on the IoTDB server, you can enable SSL when creating the connection pool and specify certificate-related parameters. + +```typescript +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 Write Redirection + +In a multi-node IoTDB cluster, the client supports write redirection. When a write operation is sent to a non-target node, the server may return a redirection hint. The client caches the target route and prefers a more suitable node for subsequent writes. + +```typescript +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(); +``` + +With redirection enabled, cross-node forwarding is reduced, improving write throughput and lowering network latency. + +### 2.2 Database Operations + +#### 2.2.1 Creating a Database and a Table + +```typescript +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 Inserting Tablet Data + +When writing in the table model, you need to specify the table name, column names, data types, timestamps, and values. The following example organizes `values` by column, where each array corresponds to a non-time column. + +```typescript +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], + ], +}); +``` + +If your project does not use the enums directly, `columnTypes` can also use data type codes. + +For data insertion, it is recommended to use `insertTablet` for batch writes to reduce network round trips. A common batch size to start with is 100 to 1000 rows, then adjust based on data volume, network, and server resources. + +#### 2.2.3 Querying Data + +Query results are returned through `SessionDataSet`. Call `close()` after use to release server-side query resources. + +```typescript +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(); +``` + +For small result sets, you can also use `toArray()` to load all results into memory: + +```typescript +const dataSet = await tablePool.executeQueryStatement('SHOW TABLES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 Closing the Connection Pool + +```typescript +await tablePool.close(); +``` + +It is recommended to close the connection pool uniformly when the application exits, a scheduled task ends, or the service is destroyed, to avoid connection leaks. + +## 3. Common Interfaces + +### 3.1 TableSessionPool + +#### 3.1.1 Description + +`TableSessionPool` is the recommended connection pool interface for the table model. It supports automatic session management and database context management. When a query, insert, or non-query method is called, the pool automatically acquires an available session and recycles the connection after execution. + +#### 3.1.2 Constructors + +| Constructor | Description | +| --- | --- | +| `new TableSessionPool(host, port, config)` | Traditional constructor, suitable for single-node connections | +| `new TableSessionPool(config)` | Constructed with a configuration object, suitable for `nodeUrls` multi-node configurations | +| `new TableSessionPool(new PoolConfigBuilder().build())` | Constructed with the builder pattern, recommended when there are many parameters | + +#### 3.1.3 Methods + +| Method | Description | +| --- | --- | +| `init()` | Initializes the connection pool | +| `close()` | Closes the connection pool and releases all connections | +| `executeQueryStatement(sql, timeoutMs?)` | Executes a query SQL, with an optional query timeout | +| `executeNonQueryStatement(sql)` | Executes a non-query SQL, such as DDL or DML | +| `insertTablet(tablet)` | Inserts table model Tablet data | +| `getPoolSize()` | Gets the current pool size | +| `getAvailableSize()` | Gets the current number of available connections | +| `getInUseSize()` | Gets the current number of connections in use | + +#### 3.1.4 Configuration Options + +| Option | Description | +| --- | --- | +| `host` | Host address | +| `port` | Port | +| `nodeUrls` | Multiple node addresses, in the format `host:port` | +| `username` | User name | +| `password` | Password | +| `database` | Default database | +| `timezone` | Time zone | +| `fetchSize` | Batch fetch size for query results | +| `maxPoolSize` | Maximum number of connections | +| `minPoolSize` | Minimum number of connections | +| `maxIdleTime` | Maximum idle time in milliseconds | +| `waitTimeout` | Wait timeout for acquiring a connection, in milliseconds | +| `enableSSL` | Whether to enable SSL | +| `sslOptions` | SSL options | +| `enableRedirection` | Whether to enable write redirection | +| `redirectCacheTTL` | Redirection cache expiration time in milliseconds | + +### 3.2 Tablet Parameters + +The common parameters of `insertTablet` in the table model are as follows: + +| Parameter | Description | +| --- | --- | +| `tableName` | Target table name | +| `columnNames` | List of non-time column names | +| `dataTypes` | List of data types for non-time columns | +| `columnCategories` | List of categories for non-time columns | +| `timestamps` | List of timestamps | +| `values` | List of column values, organized by column | + +The orders of `columnNames`, `columnTypes`, `columnCategories`, and `values` must be consistent. + +## 4. Data Types + +When inserting Tablet data, you need to specify the corresponding data type for each column. The common types supported by the Node.js client are as follows: + +| Type Code | Type Name | JavaScript Type | Description | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | Boolean value | +| `1` | `INT32` | `number` | 32-bit integer | +| `2` | `INT64` | `bigint` | 64-bit integer | +| `3` | `FLOAT` | `number` | 32-bit floating point | +| `4` | `DOUBLE` | `number` | 64-bit floating point | +| `5` | `TEXT` | `string` | UTF-8 text | +| `8` | `TIMESTAMP` | `Date` | Millisecond-precision timestamp | +| `9` | `DATE` | `Date` | Date type | +| `10` | `BLOB` | `Buffer` | Binary data | +| `11` | `STRING` | `string` | UTF-8 string | + +When handling the `INT64` type, it is recommended to use `bigint` in JavaScript to avoid precision loss when values exceed the safe integer range of `number`. + +## 5. FAQ + +1. Default database does not exist: If the configured `database` does not exist when the connection pool is initialized, first execute `CREATE DATABASE`, then explicitly execute `USE database_name` before creating tables, querying, or writing. Alternatively, create the database before initializing `TableSessionPool`. + +2. Column mismatch: If a column count or type mismatch occurs during insertion, check whether the orders and lengths of `columnNames`, `columnTypes`, `columnCategories`, and `values` are consistent, and confirm that `values` are organized by row and the table schema matches the written data. + +3. Query results consume too much memory: For large result sets, it is recommended to read in batches with `hasNext()` and `next()` and reduce `fetchSize`. Use `toArray()` only for small result sets. + +4. Connection acquisition timeout: If waiting for an available connection times out, the pool is usually exhausted. Increase `waitTimeout` or `maxPoolSize` as appropriate, and check whether there are query result sets that have not been closed for a long time. diff --git a/src/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API.md b/src/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API.md deleted file mode 100644 index a7f7aff00..000000000 --- a/src/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API.md +++ /dev/null @@ -1,181 +0,0 @@ - - -# Node.js Native API - -Apache IoTDB uses Thrift as a cross-language RPC-framework so access to IoTDB can be achieved through the interfaces provided by Thrift. -This document will introduce how to generate a native Node.js interface that can be used to access IoTDB. - -## 1. Dependents - - * JDK >= 1.8 - * Node.js >= 16.0.0 - * Linux、Macos or like unix - * Windows+bash - -## 2. Generate the Node.js native interface - -1. Find the `pom.xml` file in the root directory of the IoTDB [source code](https://github.com/apache/iotdb) folder. -2. Open the `pom.xml` file and find the following content: - ```xml - - generate-thrift-sources-python - generate-sources - - compile - - - py - ${project.build.directory}/generated-sources-python/ - - - ``` -3. Duplicate this block and change the `id`, `generator` and `outputDirectory` to this: - ```xml - - generate-thrift-sources-nodejs - generate-sources - - compile - - - js:node - ${project.build.directory}/generated-sources-nodejs/ - - - ``` -4. In the root directory of the IoTDB [source code](https://github.com/apache/iotdb) folder,run `mvn clean generate-sources`. - -This command will automatically delete the files in `iotdb/iotdb-protocol/thrift/target` and `iotdb/iotdb-protocol/thrift-commons/target`, and repopulate the folder with the newly generated files. -The newly generated JavaScript sources will be located in `iotdb/iotdb-protocol/thrift/target/generated-sources-nodejs` in the various modules of the `iotdb-protocol` module. - -## 3. Using the Node.js native interface - -Simply copy the files in `iotdb/iotdb-protocol/thrift/target/generated-sources-nodejs/` and `iotdb/iotdb-protocol/thrift-commons/target/generated-sources-nodejs/` into your project. - -## 4. rpc interface - -``` -// open a session -TSOpenSessionResp openSession(1:TSOpenSessionReq req); - -// close a session -TSStatus closeSession(1:TSCloseSessionReq req); - -// run an SQL statement in batch -TSExecuteStatementResp executeStatement(1:TSExecuteStatementReq req); - -// execute SQL statement in batch -TSStatus executeBatchStatement(1:TSExecuteBatchStatementReq req); - -// execute query SQL statement -TSExecuteStatementResp executeQueryStatement(1:TSExecuteStatementReq req); - -// execute insert, delete and update SQL statement -TSExecuteStatementResp executeUpdateStatement(1:TSExecuteStatementReq req); - -// fetch next query result -TSFetchResultsResp fetchResults(1:TSFetchResultsReq req) - -// fetch meta data -TSFetchMetadataResp fetchMetadata(1:TSFetchMetadataReq req) - -// cancel a query -TSStatus cancelOperation(1:TSCancelOperationReq req); - -// close a query dataset -TSStatus closeOperation(1:TSCloseOperationReq req); - -// get time zone -TSGetTimeZoneResp getTimeZone(1:i64 sessionId); - -// set time zone -TSStatus setTimeZone(1:TSSetTimeZoneReq req); - -// get server's properties -ServerProperties getProperties(); - -// CREATE DATABASE -TSStatus setStorageGroup(1:i64 sessionId, 2:string storageGroup); - -// create timeseries -TSStatus createTimeseries(1:TSCreateTimeseriesReq req); - -// create multi timeseries -TSStatus createMultiTimeseries(1:TSCreateMultiTimeseriesReq req); - -// delete timeseries -TSStatus deleteTimeseries(1:i64 sessionId, 2:list path) - -// delete sttorage groups -TSStatus deleteStorageGroups(1:i64 sessionId, 2:list storageGroup); - -// insert record -TSStatus insertRecord(1:TSInsertRecordReq req); - -// insert record in string format -TSStatus insertStringRecord(1:TSInsertStringRecordReq req); - -// insert tablet -TSStatus insertTablet(1:TSInsertTabletReq req); - -// insert tablets in batch -TSStatus insertTablets(1:TSInsertTabletsReq req); - -// insert records in batch -TSStatus insertRecords(1:TSInsertRecordsReq req); - -// insert records of one device -TSStatus insertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// insert records in batch as string format -TSStatus insertStringRecords(1:TSInsertStringRecordsReq req); - -// test the latency of innsert tablet,caution:no data will be inserted, only for test latency -TSStatus testInsertTablet(1:TSInsertTabletReq req); - -// test the latency of innsert tablets,caution:no data will be inserted, only for test latency -TSStatus testInsertTablets(1:TSInsertTabletsReq req); - -// test the latency of innsert record,caution:no data will be inserted, only for test latency -TSStatus testInsertRecord(1:TSInsertRecordReq req); - -// test the latency of innsert record in string format,caution:no data will be inserted, only for test latency -TSStatus testInsertStringRecord(1:TSInsertStringRecordReq req); - -// test the latency of innsert records,caution:no data will be inserted, only for test latency -TSStatus testInsertRecords(1:TSInsertRecordsReq req); - -// test the latency of innsert records of one device,caution:no data will be inserted, only for test latency -TSStatus testInsertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// test the latency of innsert records in string formate,caution:no data will be inserted, only for test latency -TSStatus testInsertStringRecords(1:TSInsertStringRecordsReq req); - -// delete data -TSStatus deleteData(1:TSDeleteDataReq req); - -// execute raw data query -TSExecuteStatementResp executeRawDataQuery(1:TSRawDataQueryReq req); - -// request a statement id from server -i64 requestStatementId(1:i64 sessionId); -``` \ No newline at end of file diff --git a/src/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API_apache.md b/src/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..10121a7ce --- /dev/null +++ b/src/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,374 @@ + + +# Node.js Native API + +The Node.js native API supports interacting with the IoTDB tree model through `Session` and `SessionPool`, enabling data insertion, queries, non-query SQL, and connection management. Since `Session` is not thread-safe, `SessionPool` is recommended for production environments. Under high concurrency, `SessionPool` manages connection resources in a unified way and supports multi-node load balancing, failover, and write redirection. + +This document focuses on the usage of `SessionPool`, covering environment preparation, core steps, and common interfaces. + +## 1. Environment Preparation + +### 1.1 Prerequisites + +* Node.js >= 14.0.0 +* npm >= 6.0.0 +* IoTDB >= 2.0.11 + +### 1.2 Installation + +* **Option 1: Install directly via npm (recommended)** + +Run the following command in your Node.js project: + +```bash +npm install @iotdb/client +``` + +* **Option 2: Build from source** + +To use the development version from the repository, clone the source code and install dependencies: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +On Linux, macOS, or WSL, run: + +```bash +npm run build +``` + +On Windows PowerShell, run: + +```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 +``` + +After the build is complete, you can install the client locally in your business project via the absolute path of the client source directory: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +If you use TypeScript, no additional type declarations are required. The client comes with complete TypeScript type definitions built in. + +**Note: Do not use a higher-version client to connect to a lower-version server.** + +## 2. Core Steps + +The three core steps of operating the IoTDB tree model with the Node.js native API are as follows: + +1. Create a connection pool instance: initialize a `SessionPool` object with connection parameters and pool size. +2. Execute database operations: perform data insertion, queries, or non-query SQL directly through the connection pool. +3. Close the connection pool: call `pool.close()` when the program ends to release all connections. + +The following sections describe the core development workflow and do not demonstrate all parameters and interfaces. For the complete capabilities, refer to the [`@iotdb/client` source code](https://github.com/apache/iotdb-client-nodejs/tree/develop/src) and [examples](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples). + +### 2.1 Creating a Connection Pool Instance + +#### 2.1.1 Single-Node Connection + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool('localhost', 6667, { + username: 'root', + password: 'root', + maxPoolSize: 10, + minPoolSize: 2, + maxIdleTime: 60000, + waitTimeout: 60000, +}); + +await pool.init(); +``` + +#### 2.1.2 Multi-Node Connection + +In a cluster environment, it is recommended to configure multiple nodes with `nodeUrls`. The connection pool distributes connections across nodes in a round-robin manner and tries other available nodes when a connection fails. + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 15, + minPoolSize: 3, +}); + +await pool.init(); +``` + +You can also create the connection pool configuration with the builder pattern: + +```typescript +import { SessionPool, PoolConfigBuilder } from '@iotdb/client'; + +const pool = new SessionPool( + new PoolConfigBuilder() + .nodeUrls([ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ]) + .username('root') + .password('root') + .maxPoolSize(15) + .minPoolSize(3) + .build() +); + +await pool.init(); +``` + +Connection pool parameters can be adjusted according to your workload: `minPoolSize` is recommended to be set to the average concurrent load, while `maxPoolSize` should be set to the peak concurrent load with a 20% to 30% buffer. `maxIdleTime` is used to clean up long-idle connections, and `waitTimeout` controls the maximum waiting time when the pool is exhausted. In production, it is recommended to monitor `getPoolSize()`, `getAvailableSize()`, and `getInUseSize()`, and adjust the pool size based on peak load. + +#### 2.1.3 SSL/TLS Connection + +If SSL/TLS is enabled on the IoTDB server, you can enable SSL when creating the connection pool and specify certificate-related parameters. + +```typescript +import { SessionPool } from '@iotdb/client'; +import * as fs from 'fs'; + +const pool = new SessionPool({ + host: 'localhost', + port: 6667, + username: 'root', + password: 'root', + 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 pool.init(); +``` + +#### 2.1.4 Write Redirection + +In a multi-node IoTDB cluster, the client supports write redirection. When a write operation is sent to a non-target node, the server may return a redirection hint. The client caches the device-to-node mapping and prefers the target node for subsequent writes to the same device. + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 10, + enableRedirection: true, + redirectCacheTTL: 300000, +}); + +await pool.init(); +``` + +With redirection enabled, cross-node forwarding is reduced, improving write throughput and lowering network latency. This capability applies to device-level write scenarios in the tree model. + +### 2.2 Database Operations + +#### 2.2.1 Creating a Database and Time Series + +```typescript +await pool.executeNonQueryStatement('CREATE DATABASE root.test'); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT, ENCODING=RLE' +); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.humidity WITH DATATYPE=FLOAT, ENCODING=RLE' +); +``` + +#### 2.2.2 Inserting Tablet Data + +`insertTablet` supports batch insertion of multiple rows per device. `values` is a two-dimensional array organized by row: each row corresponds to a timestamp, consistent with the order of `timestamps`; each column corresponds to a measurement, consistent with the order of `measurements`. + +```typescript +await pool.insertTablet({ + deviceId: 'root.test.device1', + measurements: ['temperature', 'humidity'], + dataTypes: [3, 3], + timestamps: [Date.now(), Date.now() + 1000], + values: [ + [25.5, 60.0], + [26.0, 61.5], + ], +}); +``` + +Here `dataTypes` can use data type codes, which can also be encapsulated as constants in your project. See Chapter 4 of this document for common type codes. + +For data insertion, it is recommended to use `insertTablet` for batch writes to reduce network round trips. A common batch size to start with is 100 to 1000 rows, then adjust based on data volume, network, and server resources. + +#### 2.2.3 Querying Data + +Query results are returned through `SessionDataSet`, which supports paged fetching and is suitable for large result sets. Call `close()` after use to release server-side query resources. + +```typescript +const dataSet = await pool.executeQueryStatement( + 'SELECT temperature, humidity FROM root.test.device1' +); + +while (await dataSet.hasNext()) { + const row = dataSet.next(); + console.log(row.getTimestamp(), row.getFields()); +} + +await dataSet.close(); +``` + +For small result sets, you can also use `toArray()` to load all results into memory: + +```typescript +const dataSet = await pool.executeQueryStatement('SHOW DATABASES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 Closing the Connection Pool + +```typescript +await pool.close(); +``` + +It is recommended to close the connection pool uniformly when the application exits, a scheduled task ends, or the service is destroyed, to avoid connection leaks. + +## 3. Common Interfaces + +### 3.1 SessionPool + +#### 3.1.1 Description + +`SessionPool` is the recommended connection pool interface for the tree model and supports automatic session management. When a query, insert, or non-query method is called, the pool automatically acquires an available `Session` and recycles the connection after execution. + +#### 3.1.2 Constructors + +| Constructor | Description | +| --- | --- | +| `new SessionPool(hosts, port, config)` | Traditional constructor, suitable for single-node or multi-host configurations with the same port | +| `new SessionPool(config)` | Constructed with a configuration object, suitable for `nodeUrls` multi-node configurations | +| `new SessionPool(new PoolConfigBuilder().build())` | Constructed with the builder pattern, recommended when there are many parameters | + +#### 3.1.3 Methods + +| Method | Description | +| --- | --- | +| `init()` | Initializes the connection pool | +| `close()` | Closes the connection pool and releases all connections | +| `executeQueryStatement(sql, timeoutMs?)` | Executes a query SQL, with an optional query timeout | +| `executeNonQueryStatement(sql)` | Executes a non-query SQL, such as DDL or DML | +| `insertTablet(tablet)` | Inserts Tablet data | +| `getSession()` | Acquires a `Session` from the pool, which must be returned manually | +| `releaseSession(session)` | Returns a manually acquired `Session` to the pool | +| `getPoolSize()` | Gets the current pool size | +| `getAvailableSize()` | Gets the current number of available connections | +| `getInUseSize()` | Gets the current number of connections in use | + +#### 3.1.4 Configuration Options + +| Option | Description | +| --- | --- | +| `host` | Host address | +| `port` | Port | +| `nodeUrls` | Multiple node addresses, in the format `host:port` | +| `username` | User name | +| `password` | Password | +| `database` | Default database | +| `timezone` | Time zone | +| `fetchSize` | Batch fetch size for query results | +| `maxPoolSize` | Maximum number of connections | +| `minPoolSize` | Minimum number of connections | +| `maxIdleTime` | Maximum idle time in milliseconds | +| `waitTimeout` | Wait timeout for acquiring a connection, in milliseconds | +| `enableSSL` | Whether to enable SSL | +| `sslOptions` | SSL options | +| `enableRedirection` | Whether to enable write redirection | +| `redirectCacheTTL` | Redirection cache expiration time in milliseconds | + +### 3.2 Session + +#### 3.2.1 Description + +`Session` represents an independent session, suitable for simple scripts or single-threaded scenarios. `Session` is not thread-safe; use `SessionPool` for multi-threaded or high-concurrency scenarios. + +#### 3.2.2 Methods + +| Method | Description | +| --- | --- | +| `open()` | Opens the session | +| `close()` | Closes the session | +| `executeQueryStatement(sql, timeoutMs?)` | Executes a query SQL | +| `executeNonQueryStatement(sql)` | Executes a non-query SQL | +| `insertTablet(tablet)` | Inserts Tablet data | +| `isOpen()` | Checks whether the session is open | + +## 4. Data Types + +When inserting Tablet data, you need to specify the corresponding data type for each measurement. The common types supported by the Node.js client are as follows: + +| Type Code | Type Name | JavaScript Type | Description | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | Boolean value | +| `1` | `INT32` | `number` | 32-bit integer | +| `2` | `INT64` | `bigint` | 64-bit integer | +| `3` | `FLOAT` | `number` | 32-bit floating point | +| `4` | `DOUBLE` | `number` | 64-bit floating point | +| `5` | `TEXT` | `string` | UTF-8 text | +| `8` | `TIMESTAMP` | `Date` | Millisecond-precision timestamp | +| `9` | `DATE` | `Date` | Date type | +| `10` | `BLOB` | `Buffer` | Binary data | +| `11` | `STRING` | `string` | UTF-8 string | + +When handling the `INT64` type, it is recommended to use `bigint` in JavaScript to avoid precision loss when values exceed the safe integer range of `number`. + +## 5. FAQ + +1. Connection refused: If `ECONNREFUSED` occurs, check whether the IoTDB service is running, whether the RPC port is correct, and whether the network and firewall allow access. The default port is usually `6667`. + +2. Connection acquisition timeout: If waiting for an available connection times out, the pool is usually exhausted. Increase `waitTimeout` or `maxPoolSize` as appropriate, and check whether a manually acquired `Session` is not returned via `releaseSession(session)`. + +3. Query results consume too much memory: For large result sets, it is recommended to read in batches with `hasNext()` and `next()` and reduce `fetchSize`. Use `toArray()` only for small result sets. + +4. Unstable write performance: It is recommended to use `insertTablet` for batch writes and adjust the number of rows per batch based on data volume, network, and server resources. In multi-node environments, configure `nodeUrls` so that the pool distributes load across nodes. diff --git a/src/UserGuide/latest-Table/API/Programming-NodeJS-Native-API_apache.md b/src/UserGuide/latest-Table/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..811d0e9b7 --- /dev/null +++ b/src/UserGuide/latest-Table/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,371 @@ + + +# Node.js Native API + +The Node.js native API supports interacting with the IoTDB table model through `TableSessionPool`, enabling data insertion, queries, non-query SQL, and connection management under the table model. Building on connection pool capabilities, `TableSessionPool` adds database context management, making it suitable for accessing relational table data in Node.js applications. + +This document focuses on the usage of `TableSessionPool`, covering environment preparation, core steps, and common interfaces. + +## 1. Environment Preparation + +### 1.1 Prerequisites + +* Node.js >= 14.0.0 +* npm >= 6.0.0 +* IoTDB >= 2.0.11 + +### 1.2 Installation + +* **Option 1: Install directly via npm (recommended)** + +Run the following command in your Node.js project: + +```bash +npm install @iotdb/client +``` + +* **Option 2: Build from source** + +To use the development version from the repository, clone the source code and install dependencies: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +On Linux, macOS, or WSL, run: + +```bash +npm run build +``` + +On Windows PowerShell, run: + +```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 +``` + +After the build is complete, you can install the client locally in your business project via the absolute path of the client source directory: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +If you use TypeScript, no additional type declarations are required. The client comes with complete TypeScript type definitions built in. + +**Note: Do not use a higher-version client to connect to a lower-version server.** + +## 2. Core Steps + +The three core steps of operating the IoTDB table model with the Node.js native API are as follows: + +1. Create a connection pool instance: initialize a `TableSessionPool` object with connection parameters, database, and pool size. +2. Execute database operations: perform table creation, data insertion, or queries directly through the connection pool. +3. Close the connection pool: call `tablePool.close()` when the program ends to release all connections. + +The following sections describe the core development workflow and do not demonstrate all parameters and interfaces. For the complete capabilities, refer to the [`@iotdb/client` source code](https://github.com/apache/iotdb-client-nodejs/tree/develop/src) and [examples](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples). + +### 2.1 Creating a Connection Pool Instance + +#### 2.1.1 Single-Node Connection + +```typescript +import { TableSessionPool } from '@iotdb/client'; + +const tablePool = new TableSessionPool('localhost', 6667, { + username: 'root', + password: 'root', + database: 'test', + maxPoolSize: 10, + minPoolSize: 2, +}); + +await tablePool.init(); +``` + +Here `database` sets the default database for the table model. Once configured, the connection pool uses this database context for queries and writes. + +#### 2.1.2 Multi-Node Connection + +In a cluster environment, it is recommended to configure multiple nodes with `nodeUrls`. The connection pool distributes connections across nodes in a round-robin manner and tries other available nodes when a connection fails. + +```typescript +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(); +``` + +Connection pool parameters can be adjusted according to your workload: `minPoolSize` is recommended to be set to the average concurrent load, while `maxPoolSize` should be set to the peak concurrent load with a 20% to 30% buffer. `maxIdleTime` is used to clean up long-idle connections, and `waitTimeout` controls the maximum waiting time when the pool is exhausted. In production, it is recommended to monitor `getPoolSize()`, `getAvailableSize()`, and `getInUseSize()`, and adjust the pool size based on peak load. + +#### 2.1.3 SSL/TLS Connection + +If SSL/TLS is enabled on the IoTDB server, you can enable SSL when creating the connection pool and specify certificate-related parameters. + +```typescript +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 Write Redirection + +In a multi-node IoTDB cluster, the client supports write redirection. When a write operation is sent to a non-target node, the server may return a redirection hint. The client caches the target route and prefers a more suitable node for subsequent writes. + +```typescript +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(); +``` + +With redirection enabled, cross-node forwarding is reduced, improving write throughput and lowering network latency. + +### 2.2 Database Operations + +#### 2.2.1 Creating a Database and a Table + +```typescript +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 Inserting Tablet Data + +When writing in the table model, you need to specify the table name, column names, data types, timestamps, and values. The following example organizes `values` by column, where each array corresponds to a non-time column. + +```typescript +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], + ], +}); +``` + +If your project does not use the enums directly, `columnTypes` can also use data type codes. + +For data insertion, it is recommended to use `insertTablet` for batch writes to reduce network round trips. A common batch size to start with is 100 to 1000 rows, then adjust based on data volume, network, and server resources. + +#### 2.2.3 Querying Data + +Query results are returned through `SessionDataSet`. Call `close()` after use to release server-side query resources. + +```typescript +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(); +``` + +For small result sets, you can also use `toArray()` to load all results into memory: + +```typescript +const dataSet = await tablePool.executeQueryStatement('SHOW TABLES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 Closing the Connection Pool + +```typescript +await tablePool.close(); +``` + +It is recommended to close the connection pool uniformly when the application exits, a scheduled task ends, or the service is destroyed, to avoid connection leaks. + +## 3. Common Interfaces + +### 3.1 TableSessionPool + +#### 3.1.1 Description + +`TableSessionPool` is the recommended connection pool interface for the table model. It supports automatic session management and database context management. When a query, insert, or non-query method is called, the pool automatically acquires an available session and recycles the connection after execution. + +#### 3.1.2 Constructors + +| Constructor | Description | +| --- | --- | +| `new TableSessionPool(host, port, config)` | Traditional constructor, suitable for single-node connections | +| `new TableSessionPool(config)` | Constructed with a configuration object, suitable for `nodeUrls` multi-node configurations | +| `new TableSessionPool(new PoolConfigBuilder().build())` | Constructed with the builder pattern, recommended when there are many parameters | + +#### 3.1.3 Methods + +| Method | Description | +| --- | --- | +| `init()` | Initializes the connection pool | +| `close()` | Closes the connection pool and releases all connections | +| `executeQueryStatement(sql, timeoutMs?)` | Executes a query SQL, with an optional query timeout | +| `executeNonQueryStatement(sql)` | Executes a non-query SQL, such as DDL or DML | +| `insertTablet(tablet)` | Inserts table model Tablet data | +| `getPoolSize()` | Gets the current pool size | +| `getAvailableSize()` | Gets the current number of available connections | +| `getInUseSize()` | Gets the current number of connections in use | + +#### 3.1.4 Configuration Options + +| Option | Description | +| --- | --- | +| `host` | Host address | +| `port` | Port | +| `nodeUrls` | Multiple node addresses, in the format `host:port` | +| `username` | User name | +| `password` | Password | +| `database` | Default database | +| `timezone` | Time zone | +| `fetchSize` | Batch fetch size for query results | +| `maxPoolSize` | Maximum number of connections | +| `minPoolSize` | Minimum number of connections | +| `maxIdleTime` | Maximum idle time in milliseconds | +| `waitTimeout` | Wait timeout for acquiring a connection, in milliseconds | +| `enableSSL` | Whether to enable SSL | +| `sslOptions` | SSL options | +| `enableRedirection` | Whether to enable write redirection | +| `redirectCacheTTL` | Redirection cache expiration time in milliseconds | + +### 3.2 Tablet Parameters + +The common parameters of `insertTablet` in the table model are as follows: + +| Parameter | Description | +| --- | --- | +| `tableName` | Target table name | +| `columnNames` | List of non-time column names | +| `dataTypes` | List of data types for non-time columns | +| `columnCategories` | List of categories for non-time columns | +| `timestamps` | List of timestamps | +| `values` | List of column values, organized by column | + +The orders of `columnNames`, `columnTypes`, `columnCategories`, and `values` must be consistent. + +## 4. Data Types + +When inserting Tablet data, you need to specify the corresponding data type for each column. The common types supported by the Node.js client are as follows: + +| Type Code | Type Name | JavaScript Type | Description | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | Boolean value | +| `1` | `INT32` | `number` | 32-bit integer | +| `2` | `INT64` | `bigint` | 64-bit integer | +| `3` | `FLOAT` | `number` | 32-bit floating point | +| `4` | `DOUBLE` | `number` | 64-bit floating point | +| `5` | `TEXT` | `string` | UTF-8 text | +| `8` | `TIMESTAMP` | `Date` | Millisecond-precision timestamp | +| `9` | `DATE` | `Date` | Date type | +| `10` | `BLOB` | `Buffer` | Binary data | +| `11` | `STRING` | `string` | UTF-8 string | + +When handling the `INT64` type, it is recommended to use `bigint` in JavaScript to avoid precision loss when values exceed the safe integer range of `number`. + +## 5. FAQ + +1. Default database does not exist: If the configured `database` does not exist when the connection pool is initialized, first execute `CREATE DATABASE`, then explicitly execute `USE database_name` before creating tables, querying, or writing. Alternatively, create the database before initializing `TableSessionPool`. + +2. Column mismatch: If a column count or type mismatch occurs during insertion, check whether the orders and lengths of `columnNames`, `columnTypes`, `columnCategories`, and `values` are consistent, and confirm that `values` are organized by row and the table schema matches the written data. + +3. Query results consume too much memory: For large result sets, it is recommended to read in batches with `hasNext()` and `next()` and reduce `fetchSize`. Use `toArray()` only for small result sets. + +4. Connection acquisition timeout: If waiting for an available connection times out, the pool is usually exhausted. Increase `waitTimeout` or `maxPoolSize` as appropriate, and check whether there are query result sets that have not been closed for a long time. diff --git a/src/UserGuide/latest/API/Programming-NodeJS-Native-API.md b/src/UserGuide/latest/API/Programming-NodeJS-Native-API.md deleted file mode 100644 index a7f7aff00..000000000 --- a/src/UserGuide/latest/API/Programming-NodeJS-Native-API.md +++ /dev/null @@ -1,181 +0,0 @@ - - -# Node.js Native API - -Apache IoTDB uses Thrift as a cross-language RPC-framework so access to IoTDB can be achieved through the interfaces provided by Thrift. -This document will introduce how to generate a native Node.js interface that can be used to access IoTDB. - -## 1. Dependents - - * JDK >= 1.8 - * Node.js >= 16.0.0 - * Linux、Macos or like unix - * Windows+bash - -## 2. Generate the Node.js native interface - -1. Find the `pom.xml` file in the root directory of the IoTDB [source code](https://github.com/apache/iotdb) folder. -2. Open the `pom.xml` file and find the following content: - ```xml - - generate-thrift-sources-python - generate-sources - - compile - - - py - ${project.build.directory}/generated-sources-python/ - - - ``` -3. Duplicate this block and change the `id`, `generator` and `outputDirectory` to this: - ```xml - - generate-thrift-sources-nodejs - generate-sources - - compile - - - js:node - ${project.build.directory}/generated-sources-nodejs/ - - - ``` -4. In the root directory of the IoTDB [source code](https://github.com/apache/iotdb) folder,run `mvn clean generate-sources`. - -This command will automatically delete the files in `iotdb/iotdb-protocol/thrift/target` and `iotdb/iotdb-protocol/thrift-commons/target`, and repopulate the folder with the newly generated files. -The newly generated JavaScript sources will be located in `iotdb/iotdb-protocol/thrift/target/generated-sources-nodejs` in the various modules of the `iotdb-protocol` module. - -## 3. Using the Node.js native interface - -Simply copy the files in `iotdb/iotdb-protocol/thrift/target/generated-sources-nodejs/` and `iotdb/iotdb-protocol/thrift-commons/target/generated-sources-nodejs/` into your project. - -## 4. rpc interface - -``` -// open a session -TSOpenSessionResp openSession(1:TSOpenSessionReq req); - -// close a session -TSStatus closeSession(1:TSCloseSessionReq req); - -// run an SQL statement in batch -TSExecuteStatementResp executeStatement(1:TSExecuteStatementReq req); - -// execute SQL statement in batch -TSStatus executeBatchStatement(1:TSExecuteBatchStatementReq req); - -// execute query SQL statement -TSExecuteStatementResp executeQueryStatement(1:TSExecuteStatementReq req); - -// execute insert, delete and update SQL statement -TSExecuteStatementResp executeUpdateStatement(1:TSExecuteStatementReq req); - -// fetch next query result -TSFetchResultsResp fetchResults(1:TSFetchResultsReq req) - -// fetch meta data -TSFetchMetadataResp fetchMetadata(1:TSFetchMetadataReq req) - -// cancel a query -TSStatus cancelOperation(1:TSCancelOperationReq req); - -// close a query dataset -TSStatus closeOperation(1:TSCloseOperationReq req); - -// get time zone -TSGetTimeZoneResp getTimeZone(1:i64 sessionId); - -// set time zone -TSStatus setTimeZone(1:TSSetTimeZoneReq req); - -// get server's properties -ServerProperties getProperties(); - -// CREATE DATABASE -TSStatus setStorageGroup(1:i64 sessionId, 2:string storageGroup); - -// create timeseries -TSStatus createTimeseries(1:TSCreateTimeseriesReq req); - -// create multi timeseries -TSStatus createMultiTimeseries(1:TSCreateMultiTimeseriesReq req); - -// delete timeseries -TSStatus deleteTimeseries(1:i64 sessionId, 2:list path) - -// delete sttorage groups -TSStatus deleteStorageGroups(1:i64 sessionId, 2:list storageGroup); - -// insert record -TSStatus insertRecord(1:TSInsertRecordReq req); - -// insert record in string format -TSStatus insertStringRecord(1:TSInsertStringRecordReq req); - -// insert tablet -TSStatus insertTablet(1:TSInsertTabletReq req); - -// insert tablets in batch -TSStatus insertTablets(1:TSInsertTabletsReq req); - -// insert records in batch -TSStatus insertRecords(1:TSInsertRecordsReq req); - -// insert records of one device -TSStatus insertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// insert records in batch as string format -TSStatus insertStringRecords(1:TSInsertStringRecordsReq req); - -// test the latency of innsert tablet,caution:no data will be inserted, only for test latency -TSStatus testInsertTablet(1:TSInsertTabletReq req); - -// test the latency of innsert tablets,caution:no data will be inserted, only for test latency -TSStatus testInsertTablets(1:TSInsertTabletsReq req); - -// test the latency of innsert record,caution:no data will be inserted, only for test latency -TSStatus testInsertRecord(1:TSInsertRecordReq req); - -// test the latency of innsert record in string format,caution:no data will be inserted, only for test latency -TSStatus testInsertStringRecord(1:TSInsertStringRecordReq req); - -// test the latency of innsert records,caution:no data will be inserted, only for test latency -TSStatus testInsertRecords(1:TSInsertRecordsReq req); - -// test the latency of innsert records of one device,caution:no data will be inserted, only for test latency -TSStatus testInsertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// test the latency of innsert records in string formate,caution:no data will be inserted, only for test latency -TSStatus testInsertStringRecords(1:TSInsertStringRecordsReq req); - -// delete data -TSStatus deleteData(1:TSDeleteDataReq req); - -// execute raw data query -TSExecuteStatementResp executeRawDataQuery(1:TSRawDataQueryReq req); - -// request a statement id from server -i64 requestStatementId(1:i64 sessionId); -``` \ No newline at end of file diff --git a/src/UserGuide/latest/API/Programming-NodeJS-Native-API_apache.md b/src/UserGuide/latest/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..10121a7ce --- /dev/null +++ b/src/UserGuide/latest/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,374 @@ + + +# Node.js Native API + +The Node.js native API supports interacting with the IoTDB tree model through `Session` and `SessionPool`, enabling data insertion, queries, non-query SQL, and connection management. Since `Session` is not thread-safe, `SessionPool` is recommended for production environments. Under high concurrency, `SessionPool` manages connection resources in a unified way and supports multi-node load balancing, failover, and write redirection. + +This document focuses on the usage of `SessionPool`, covering environment preparation, core steps, and common interfaces. + +## 1. Environment Preparation + +### 1.1 Prerequisites + +* Node.js >= 14.0.0 +* npm >= 6.0.0 +* IoTDB >= 2.0.11 + +### 1.2 Installation + +* **Option 1: Install directly via npm (recommended)** + +Run the following command in your Node.js project: + +```bash +npm install @iotdb/client +``` + +* **Option 2: Build from source** + +To use the development version from the repository, clone the source code and install dependencies: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +On Linux, macOS, or WSL, run: + +```bash +npm run build +``` + +On Windows PowerShell, run: + +```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 +``` + +After the build is complete, you can install the client locally in your business project via the absolute path of the client source directory: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +If you use TypeScript, no additional type declarations are required. The client comes with complete TypeScript type definitions built in. + +**Note: Do not use a higher-version client to connect to a lower-version server.** + +## 2. Core Steps + +The three core steps of operating the IoTDB tree model with the Node.js native API are as follows: + +1. Create a connection pool instance: initialize a `SessionPool` object with connection parameters and pool size. +2. Execute database operations: perform data insertion, queries, or non-query SQL directly through the connection pool. +3. Close the connection pool: call `pool.close()` when the program ends to release all connections. + +The following sections describe the core development workflow and do not demonstrate all parameters and interfaces. For the complete capabilities, refer to the [`@iotdb/client` source code](https://github.com/apache/iotdb-client-nodejs/tree/develop/src) and [examples](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples). + +### 2.1 Creating a Connection Pool Instance + +#### 2.1.1 Single-Node Connection + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool('localhost', 6667, { + username: 'root', + password: 'root', + maxPoolSize: 10, + minPoolSize: 2, + maxIdleTime: 60000, + waitTimeout: 60000, +}); + +await pool.init(); +``` + +#### 2.1.2 Multi-Node Connection + +In a cluster environment, it is recommended to configure multiple nodes with `nodeUrls`. The connection pool distributes connections across nodes in a round-robin manner and tries other available nodes when a connection fails. + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 15, + minPoolSize: 3, +}); + +await pool.init(); +``` + +You can also create the connection pool configuration with the builder pattern: + +```typescript +import { SessionPool, PoolConfigBuilder } from '@iotdb/client'; + +const pool = new SessionPool( + new PoolConfigBuilder() + .nodeUrls([ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ]) + .username('root') + .password('root') + .maxPoolSize(15) + .minPoolSize(3) + .build() +); + +await pool.init(); +``` + +Connection pool parameters can be adjusted according to your workload: `minPoolSize` is recommended to be set to the average concurrent load, while `maxPoolSize` should be set to the peak concurrent load with a 20% to 30% buffer. `maxIdleTime` is used to clean up long-idle connections, and `waitTimeout` controls the maximum waiting time when the pool is exhausted. In production, it is recommended to monitor `getPoolSize()`, `getAvailableSize()`, and `getInUseSize()`, and adjust the pool size based on peak load. + +#### 2.1.3 SSL/TLS Connection + +If SSL/TLS is enabled on the IoTDB server, you can enable SSL when creating the connection pool and specify certificate-related parameters. + +```typescript +import { SessionPool } from '@iotdb/client'; +import * as fs from 'fs'; + +const pool = new SessionPool({ + host: 'localhost', + port: 6667, + username: 'root', + password: 'root', + 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 pool.init(); +``` + +#### 2.1.4 Write Redirection + +In a multi-node IoTDB cluster, the client supports write redirection. When a write operation is sent to a non-target node, the server may return a redirection hint. The client caches the device-to-node mapping and prefers the target node for subsequent writes to the same device. + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 10, + enableRedirection: true, + redirectCacheTTL: 300000, +}); + +await pool.init(); +``` + +With redirection enabled, cross-node forwarding is reduced, improving write throughput and lowering network latency. This capability applies to device-level write scenarios in the tree model. + +### 2.2 Database Operations + +#### 2.2.1 Creating a Database and Time Series + +```typescript +await pool.executeNonQueryStatement('CREATE DATABASE root.test'); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT, ENCODING=RLE' +); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.humidity WITH DATATYPE=FLOAT, ENCODING=RLE' +); +``` + +#### 2.2.2 Inserting Tablet Data + +`insertTablet` supports batch insertion of multiple rows per device. `values` is a two-dimensional array organized by row: each row corresponds to a timestamp, consistent with the order of `timestamps`; each column corresponds to a measurement, consistent with the order of `measurements`. + +```typescript +await pool.insertTablet({ + deviceId: 'root.test.device1', + measurements: ['temperature', 'humidity'], + dataTypes: [3, 3], + timestamps: [Date.now(), Date.now() + 1000], + values: [ + [25.5, 60.0], + [26.0, 61.5], + ], +}); +``` + +Here `dataTypes` can use data type codes, which can also be encapsulated as constants in your project. See Chapter 4 of this document for common type codes. + +For data insertion, it is recommended to use `insertTablet` for batch writes to reduce network round trips. A common batch size to start with is 100 to 1000 rows, then adjust based on data volume, network, and server resources. + +#### 2.2.3 Querying Data + +Query results are returned through `SessionDataSet`, which supports paged fetching and is suitable for large result sets. Call `close()` after use to release server-side query resources. + +```typescript +const dataSet = await pool.executeQueryStatement( + 'SELECT temperature, humidity FROM root.test.device1' +); + +while (await dataSet.hasNext()) { + const row = dataSet.next(); + console.log(row.getTimestamp(), row.getFields()); +} + +await dataSet.close(); +``` + +For small result sets, you can also use `toArray()` to load all results into memory: + +```typescript +const dataSet = await pool.executeQueryStatement('SHOW DATABASES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 Closing the Connection Pool + +```typescript +await pool.close(); +``` + +It is recommended to close the connection pool uniformly when the application exits, a scheduled task ends, or the service is destroyed, to avoid connection leaks. + +## 3. Common Interfaces + +### 3.1 SessionPool + +#### 3.1.1 Description + +`SessionPool` is the recommended connection pool interface for the tree model and supports automatic session management. When a query, insert, or non-query method is called, the pool automatically acquires an available `Session` and recycles the connection after execution. + +#### 3.1.2 Constructors + +| Constructor | Description | +| --- | --- | +| `new SessionPool(hosts, port, config)` | Traditional constructor, suitable for single-node or multi-host configurations with the same port | +| `new SessionPool(config)` | Constructed with a configuration object, suitable for `nodeUrls` multi-node configurations | +| `new SessionPool(new PoolConfigBuilder().build())` | Constructed with the builder pattern, recommended when there are many parameters | + +#### 3.1.3 Methods + +| Method | Description | +| --- | --- | +| `init()` | Initializes the connection pool | +| `close()` | Closes the connection pool and releases all connections | +| `executeQueryStatement(sql, timeoutMs?)` | Executes a query SQL, with an optional query timeout | +| `executeNonQueryStatement(sql)` | Executes a non-query SQL, such as DDL or DML | +| `insertTablet(tablet)` | Inserts Tablet data | +| `getSession()` | Acquires a `Session` from the pool, which must be returned manually | +| `releaseSession(session)` | Returns a manually acquired `Session` to the pool | +| `getPoolSize()` | Gets the current pool size | +| `getAvailableSize()` | Gets the current number of available connections | +| `getInUseSize()` | Gets the current number of connections in use | + +#### 3.1.4 Configuration Options + +| Option | Description | +| --- | --- | +| `host` | Host address | +| `port` | Port | +| `nodeUrls` | Multiple node addresses, in the format `host:port` | +| `username` | User name | +| `password` | Password | +| `database` | Default database | +| `timezone` | Time zone | +| `fetchSize` | Batch fetch size for query results | +| `maxPoolSize` | Maximum number of connections | +| `minPoolSize` | Minimum number of connections | +| `maxIdleTime` | Maximum idle time in milliseconds | +| `waitTimeout` | Wait timeout for acquiring a connection, in milliseconds | +| `enableSSL` | Whether to enable SSL | +| `sslOptions` | SSL options | +| `enableRedirection` | Whether to enable write redirection | +| `redirectCacheTTL` | Redirection cache expiration time in milliseconds | + +### 3.2 Session + +#### 3.2.1 Description + +`Session` represents an independent session, suitable for simple scripts or single-threaded scenarios. `Session` is not thread-safe; use `SessionPool` for multi-threaded or high-concurrency scenarios. + +#### 3.2.2 Methods + +| Method | Description | +| --- | --- | +| `open()` | Opens the session | +| `close()` | Closes the session | +| `executeQueryStatement(sql, timeoutMs?)` | Executes a query SQL | +| `executeNonQueryStatement(sql)` | Executes a non-query SQL | +| `insertTablet(tablet)` | Inserts Tablet data | +| `isOpen()` | Checks whether the session is open | + +## 4. Data Types + +When inserting Tablet data, you need to specify the corresponding data type for each measurement. The common types supported by the Node.js client are as follows: + +| Type Code | Type Name | JavaScript Type | Description | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | Boolean value | +| `1` | `INT32` | `number` | 32-bit integer | +| `2` | `INT64` | `bigint` | 64-bit integer | +| `3` | `FLOAT` | `number` | 32-bit floating point | +| `4` | `DOUBLE` | `number` | 64-bit floating point | +| `5` | `TEXT` | `string` | UTF-8 text | +| `8` | `TIMESTAMP` | `Date` | Millisecond-precision timestamp | +| `9` | `DATE` | `Date` | Date type | +| `10` | `BLOB` | `Buffer` | Binary data | +| `11` | `STRING` | `string` | UTF-8 string | + +When handling the `INT64` type, it is recommended to use `bigint` in JavaScript to avoid precision loss when values exceed the safe integer range of `number`. + +## 5. FAQ + +1. Connection refused: If `ECONNREFUSED` occurs, check whether the IoTDB service is running, whether the RPC port is correct, and whether the network and firewall allow access. The default port is usually `6667`. + +2. Connection acquisition timeout: If waiting for an available connection times out, the pool is usually exhausted. Increase `waitTimeout` or `maxPoolSize` as appropriate, and check whether a manually acquired `Session` is not returned via `releaseSession(session)`. + +3. Query results consume too much memory: For large result sets, it is recommended to read in batches with `hasNext()` and `next()` and reduce `fetchSize`. Use `toArray()` only for small result sets. + +4. Unstable write performance: It is recommended to use `insertTablet` for batch writes and adjust the number of rows per batch based on data volume, network, and server resources. In multi-node environments, configure `nodeUrls` so that the pool distributes load across nodes. diff --git a/src/zh/UserGuide/Master/Table/API/Programming-NodeJS-Native-API_apache.md b/src/zh/UserGuide/Master/Table/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..2c731db4e --- /dev/null +++ b/src/zh/UserGuide/Master/Table/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,371 @@ + + +# 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 项目中执行: + +```bash +npm install @iotdb/client +``` + +* **方式二:从源码构建** + +如需使用仓库中的开发版本,可克隆源码并安装依赖: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +Linux、macOS 或 WSL 环境执行: + +```bash +npm run build +``` + +Windows PowerShell 环境执行: + +```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 +``` + +构建完成后,可在业务项目中通过客户端源码目录的绝对路径进行本地安装: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +如使用 TypeScript,无需额外安装类型声明,客户端已内置完整的 TypeScript 类型定义。 + +**注意:请勿使用高版本客户端连接低版本服务。** + +## 2. 核心步骤 + +使用 Node.js 原生接口操作 IoTDB 表模型的三个核心步骤如下: + +1. 创建连接池实例:初始化一个 `TableSessionPool` 对象,配置连接参数、数据库和池大小。 +2. 执行数据库操作:直接通过连接池执行表创建、数据写入或查询等操作。 +3. 关闭连接池资源:程序结束时调用 `tablePool.close()`,释放所有连接。 + +下面的章节用于说明开发的核心流程,并未演示所有参数和接口。如需了解完整能力,可查阅 [`@iotdb/client` 源码](https://github.com/apache/iotdb-client-nodejs/tree/develop/src)及[示例](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples)。 + +### 2.1 创建连接池实例 + +#### 2.1.1 单节点连接 + +```typescript +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` 配置多个节点。连接池会以轮询方式在多个节点间分配连接,并在连接失败时尝试其他可用节点。 + +```typescript +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,并指定证书相关参数。 + +```typescript +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 集群中,客户端支持写入重定向。写入操作发送到非目标节点时,服务端可能返回重定向建议,客户端会缓存目标路由,并在后续写入时优先使用更合适的节点。 + +```typescript +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 创建数据库和表 + +```typescript +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`,每个数组对应一个非时间列。 + +```typescript +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()` 释放服务端查询资源。 + +```typescript +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()` 将全部结果加载到内存: + +```typescript +const dataSet = await tablePool.executeQueryStatement('SHOW TABLES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 关闭连接池 + +```typescript +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 类型 | 说明 | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | 布尔值 | +| `1` | `INT32` | `number` | 32 位整数 | +| `2` | `INT64` | `bigint` | 64 位整数 | +| `3` | `FLOAT` | `number` | 32 位浮点数 | +| `4` | `DOUBLE` | `number` | 64 位浮点数 | +| `5` | `TEXT` | `string` | UTF-8 文本 | +| `8` | `TIMESTAMP` | `Date` | 毫秒精度时间戳 | +| `9` | `DATE` | `Date` | 日期类型 | +| `10` | `BLOB` | `Buffer` | 二进制数据 | +| `11` | `STRING` | `string` | UTF-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`,同时检查是否存在长时间未关闭的查询结果集。 diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API.md b/src/zh/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API.md deleted file mode 100644 index ccb096228..000000000 --- a/src/zh/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API.md +++ /dev/null @@ -1,201 +0,0 @@ - - - -# Node.js 原生接口 - -IoTDB 使用 Thrift 作为跨语言的 RPC 框架,因此可以通过 Thrift 提供的接口来实现对 IoTDB 的访问。本文档将介绍如何生成可访问 IoTDB 的原生 Node.js 接口。 - - -## 1. 依赖 - - * JDK >= 1.8 - * Node.js >= 16.0.0 - * thrift 0.14.1 - * Linux、Macos 或其他类 unix 系统 - * Windows+bash (下载 IoTDB Go client 需要 git ,通过 WSL、cygwin、Git Bash 任意一种方式均可) - -必须安装 thrift(0.14.1 或更高版本)才能将 thrift 文件编译为 Node.js 代码。下面是官方的安装教程,最终,您应该得到一个 thrift 可执行文件。 - -``` -http://thrift.apache.org/docs/install/ -``` - - -## 2. 编译 thrift 库,生成 Node.js 原生接口 - -1. 在 IoTDB [源代码](https://github.com/apache/iotdb) 文件夹的根目录中找到 pom.xml 文件。 -2. 打开 pom.xml 文件,找到以下内容: - -```xml - - generate-thrift-sources-java - generate-sources - - compile - - - java - ${thrift.exec.absolute.path} - ${basedir}/src/main/thrift - - -``` -3. 参考该设置,在 pom.xml 文件中添加以下内容,用来生成 Node.js 的原生接口: - -```xml - - generate-thrift-sources-nodejs - generate-sources - - compile - - - js:node - ${thrift.exec.absolute.path} - ${basedir}/src/main/thrift - **/common.thrift,**/client.thrift - ${project.build.directory}/generated-sources-nodejs - - -``` - -4. 在 IoTDB [源代码](https://github.com/apache/iotdb) 文件夹的根目录下,运行`mvn clean generate-sources`, - -这个指令将自动删除`iotdb/iotdb-protocol/thrift/target` 和 `iotdb/iotdb-protocol/thrift-commons/target`中的文件,并使用新生成的 thrift 文件重新填充该文件夹。 - -这个文件夹在 git 中会被忽略,并且**永远不应该被推到 git 中!** - -**注意**不要将`iotdb/iotdb-protocol/thrift/target` 和 `iotdb/iotdb-protocol/thrift-commons/target`上传到 git 仓库中 ! - -## 3. 使用 Node.js 原生接口 - -将 `iotdb/iotdb-protocol/thrift/target/generated-sources-nodejs/` 和 `iotdb/iotdb-protocol/thrift-commons/target/generated-sources-nodejs/` 中的文件复制到您的项目中,即可使用。 - - -## 4. 支持的 rpc 接口 - -``` -// 打开一个 session -TSOpenSessionResp openSession(1:TSOpenSessionReq req); - -// 关闭一个 session -TSStatus closeSession(1:TSCloseSessionReq req); - -// 执行一条 SQL 语句 -TSExecuteStatementResp executeStatement(1:TSExecuteStatementReq req); - -// 批量执行 SQL 语句 -TSStatus executeBatchStatement(1:TSExecuteBatchStatementReq req); - -// 执行查询 SQL 语句 -TSExecuteStatementResp executeQueryStatement(1:TSExecuteStatementReq req); - -// 执行插入、删除 SQL 语句 -TSExecuteStatementResp executeUpdateStatement(1:TSExecuteStatementReq req); - -// 向服务器取下一批查询结果 -TSFetchResultsResp fetchResults(1:TSFetchResultsReq req) - -// 获取元数据 -TSFetchMetadataResp fetchMetadata(1:TSFetchMetadataReq req) - -// 取消某次查询操作 -TSStatus cancelOperation(1:TSCancelOperationReq req); - -// 关闭查询操作数据集,释放资源 -TSStatus closeOperation(1:TSCloseOperationReq req); - -// 获取时区信息 -TSGetTimeZoneResp getTimeZone(1:i64 sessionId); - -// 设置时区 -TSStatus setTimeZone(1:TSSetTimeZoneReq req); - -// 获取服务端配置 -ServerProperties getProperties(); - -// 设置 database -TSStatus setStorageGroup(1:i64 sessionId, 2:string storageGroup); - -// 创建时间序列 -TSStatus createTimeseries(1:TSCreateTimeseriesReq req); - -// 创建多条时间序列 -TSStatus createMultiTimeseries(1:TSCreateMultiTimeseriesReq req); - -// 删除时间序列 -TSStatus deleteTimeseries(1:i64 sessionId, 2:list path) - -// 删除 database -TSStatus deleteStorageGroups(1:i64 sessionId, 2:list storageGroup); - -// 按行插入数据 -TSStatus insertRecord(1:TSInsertRecordReq req); - -// 按 String 格式插入一条数据 -TSStatus insertStringRecord(1:TSInsertStringRecordReq req); - -// 按列插入数据 -TSStatus insertTablet(1:TSInsertTabletReq req); - -// 按列批量插入数据 -TSStatus insertTablets(1:TSInsertTabletsReq req); - -// 按行批量插入数据 -TSStatus insertRecords(1:TSInsertRecordsReq req); - -// 按行批量插入同属于某个设备的数据 -TSStatus insertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// 按 String 格式批量按行插入数据 -TSStatus insertStringRecords(1:TSInsertStringRecordsReq req); - -// 测试按列插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertTablet(1:TSInsertTabletReq req); - -// 测试批量按列插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertTablets(1:TSInsertTabletsReq req); - -// 测试按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertRecord(1:TSInsertRecordReq req); - -// 测试按 String 格式按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertStringRecord(1:TSInsertStringRecordReq req); - -// 测试按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertRecords(1:TSInsertRecordsReq req); - -// 测试按行批量插入同属于某个设备的数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// 测试按 String 格式批量按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertStringRecords(1:TSInsertStringRecordsReq req); - -// 删除数据 -TSStatus deleteData(1:TSDeleteDataReq req); - -// 执行原始数据查询 -TSExecuteStatementResp executeRawDataQuery(1:TSRawDataQueryReq req); - -// 向服务器申请一个查询语句 ID -i64 requestStatementId(1:i64 sessionId); -``` diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API_apache.md b/src/zh/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..3200106d9 --- /dev/null +++ b/src/zh/UserGuide/Master/Tree/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,374 @@ + + +# Node.js 原生接口 + +Node.js 原生 API 支持通过 `Session` 和 `SessionPool` 两种方式与 IoTDB 树模型进行交互,可执行数据写入、查询、非查询 SQL 以及连接管理等操作。由于 `Session` 非线程安全,生产环境推荐使用 `SessionPool` 编程。在高并发场景下,`SessionPool` 能够统一管理连接资源,并支持多节点负载均衡、故障转移和写入重定向。 + +本文将围绕 `SessionPool` 的使用进行说明,涵盖从环境准备、核心操作步骤到常用接口的完整内容。 + +## 1. 环境准备 + +### 1.1 前置依赖 + +* Node.js >= 14.0.0 +* npm >= 6.0.0 +* IoTDB >= 2.0.11 + +### 1.2 安装方法 + +* **方式一:通过 npm 直接安装(推荐)** + +在 Node.js 项目中执行: + +```bash +npm install @iotdb/client +``` + +* **方式二:从源码构建** + +如需使用仓库中的开发版本,可克隆源码并安装依赖: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +Linux、macOS 或 WSL 环境执行: + +```bash +npm run build +``` + +Windows PowerShell 环境执行: + +```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 +``` + +构建完成后,可在业务项目中通过客户端源码目录的绝对路径进行本地安装: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +如使用 TypeScript,无需额外安装类型声明,客户端已内置完整的 TypeScript 类型定义。 + +**注意:请勿使用高版本客户端连接低版本服务。** + +## 2. 核心步骤 + +使用 Node.js 原生接口操作 IoTDB 树模型的三个核心步骤如下: + +1. 创建连接池实例:初始化一个 `SessionPool` 对象,配置连接参数和池大小。 +2. 执行数据库操作:直接通过连接池执行数据写入、查询或非查询 SQL。 +3. 关闭连接池资源:程序结束时调用 `pool.close()`,释放所有连接。 + +下面的章节用于说明开发的核心流程,并未演示所有参数和接口。如需了解完整能力,可查阅 [`@iotdb/client` 源码](https://github.com/apache/iotdb-client-nodejs/tree/develop/src)及[示例](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples)。 + +### 2.1 创建连接池实例 + +#### 2.1.1 单节点连接 + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool('localhost', 6667, { + username: 'root', + password: 'root', + maxPoolSize: 10, + minPoolSize: 2, + maxIdleTime: 60000, + waitTimeout: 60000, +}); + +await pool.init(); +``` + +#### 2.1.2 多节点连接 + +在集群环境下,推荐使用 `nodeUrls` 配置多个节点。连接池会以轮询方式在多个节点间分配连接,并在连接失败时尝试其他可用节点。 + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 15, + minPoolSize: 3, +}); + +await pool.init(); +``` + +也可以使用构建器模式创建连接池配置: + +```typescript +import { SessionPool, PoolConfigBuilder } from '@iotdb/client'; + +const pool = new SessionPool( + new PoolConfigBuilder() + .nodeUrls([ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ]) + .username('root') + .password('root') + .maxPoolSize(15) + .minPoolSize(3) + .build() +); + +await pool.init(); +``` + +连接池参数可按业务并发量调整:`minPoolSize` 建议设置为平均并发负载,`maxPoolSize` 建议设置为峰值并发负载并预留 20% 到 30% 缓冲;`maxIdleTime` 用于清理长期空闲连接,`waitTimeout` 用于控制连接池耗尽时的最大等待时间。生产环境建议监控 `getPoolSize()`、`getAvailableSize()` 和 `getInUseSize()`,根据峰值负载调整连接池大小。 + +#### 2.1.3 SSL/TLS 连接 + +如 IoTDB 服务端启用了 SSL/TLS,可在创建连接池时开启 SSL,并指定证书相关参数。 + +```typescript +import { SessionPool } from '@iotdb/client'; +import * as fs from 'fs'; + +const pool = new SessionPool({ + host: 'localhost', + port: 6667, + username: 'root', + password: 'root', + 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 pool.init(); +``` + +#### 2.1.4 写入重定向 + +在多节点 IoTDB 集群中,客户端支持写入重定向。写入操作发送到非目标节点时,服务端可能返回重定向建议,客户端会缓存设备到节点的映射,并在后续写入同一设备时优先使用目标节点。 + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 10, + enableRedirection: true, + redirectCacheTTL: 300000, +}); + +await pool.init(); +``` + +启用重定向后,可减少跨节点转发,提升写入吞吐并降低网络延迟。该能力适用于树模型中的设备级写入场景。 + +### 2.2 数据库操作 + +#### 2.2.1 创建数据库和时间序列 + +```typescript +await pool.executeNonQueryStatement('CREATE DATABASE root.test'); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT, ENCODING=RLE' +); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.humidity WITH DATATYPE=FLOAT, ENCODING=RLE' +); +``` + +#### 2.2.2 写入 Tablet 数据 + +`insertTablet` 支持按设备批量写入多行数据。`values` 为二维数组,按行组织数据:每行对应一个时间戳,与 `timestamps` 顺序一致;每列对应一个测点,与 `measurements` 顺序一致。 + +```typescript +await pool.insertTablet({ + deviceId: 'root.test.device1', + measurements: ['temperature', 'humidity'], + dataTypes: [3, 3], + timestamps: [Date.now(), Date.now() + 1000], + values: [ + [25.5, 60.0], + [26.0, 61.5], + ], +}); +``` + +其中 `dataTypes` 可使用数据类型编码,也可在项目中封装为常量使用。常用类型编码见本文第 4 章。 + +写入数据时建议优先使用 `insertTablet` 批量写入,减少网络往返次数;常见批量大小可从 100 到 1000 行开始压测,再根据数据规模、网络和服务端资源调整。 + +#### 2.2.3 查询数据 + +查询结果通过 `SessionDataSet` 返回,支持分页拉取,适合处理较大的结果集。使用完成后应调用 `close()` 释放服务端查询资源。 + +```typescript +const dataSet = await pool.executeQueryStatement( + 'SELECT temperature, humidity FROM root.test.device1' +); + +while (await dataSet.hasNext()) { + const row = dataSet.next(); + console.log(row.getTimestamp(), row.getFields()); +} + +await dataSet.close(); +``` + +对于小型结果集,也可以使用 `toArray()` 将全部结果加载到内存: + +```typescript +const dataSet = await pool.executeQueryStatement('SHOW DATABASES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 关闭连接池 + +```typescript +await pool.close(); +``` + +建议在应用退出、定时任务结束或服务销毁时统一关闭连接池,避免连接泄漏。 + +## 3. 常用接口 + +### 3.1 SessionPool + +#### 3.1.1 功能描述 + +`SessionPool` 是树模型推荐使用的连接池接口,支持自动会话管理。调用查询、写入或非查询方法时,连接池会自动获取可用 `Session`,执行完成后回收连接。 + +#### 3.1.2 构造方式 + +| 构造方式 | 说明 | +| --- | --- | +| `new SessionPool(hosts, port, config)` | 传统构造方式,适用于单节点或同端口多主机配置 | +| `new SessionPool(config)` | 使用配置对象构造,适合 `nodeUrls` 多节点配置 | +| `new SessionPool(new PoolConfigBuilder().build())` | 使用构建器模式构造,推荐用于参数较多的场景 | + +#### 3.1.3 方法列表 + +| 方法名 | 描述 | +| --- | --- | +| `init()` | 初始化连接池 | +| `close()` | 关闭连接池并释放所有连接 | +| `executeQueryStatement(sql, timeoutMs?)` | 执行查询 SQL,可设置查询超时时间 | +| `executeNonQueryStatement(sql)` | 执行非查询 SQL,例如 DDL 或 DML | +| `insertTablet(tablet)` | 插入 Tablet 数据 | +| `getSession()` | 从连接池中获取一个 `Session`,需要手动归还 | +| `releaseSession(session)` | 将手动获取的 `Session` 释放回连接池 | +| `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 Session + +#### 3.2.1 功能描述 + +`Session` 表示一个独立会话,适用于简单脚本或单线程场景。`Session` 非线程安全,多线程或高并发场景请使用 `SessionPool`。 + +#### 3.2.2 方法列表 + +| 方法名 | 描述 | +| --- | --- | +| `open()` | 打开会话 | +| `close()` | 关闭会话 | +| `executeQueryStatement(sql, timeoutMs?)` | 执行查询 SQL | +| `executeNonQueryStatement(sql)` | 执行非查询 SQL | +| `insertTablet(tablet)` | 插入 Tablet 数据 | +| `isOpen()` | 判断会话是否已打开 | + +## 4. 数据类型 + +插入 Tablet 数据时,需要为每个测点指定对应的数据类型。Node.js 客户端支持的常用类型如下: + +| 类型编码 | 类型名称 | JavaScript 类型 | 说明 | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | 布尔值 | +| `1` | `INT32` | `number` | 32 位整数 | +| `2` | `INT64` | `bigint` | 64 位整数 | +| `3` | `FLOAT` | `number` | 32 位浮点数 | +| `4` | `DOUBLE` | `number` | 64 位浮点数 | +| `5` | `TEXT` | `string` | UTF-8 文本 | +| `8` | `TIMESTAMP` | `Date` | 毫秒精度时间戳 | +| `9` | `DATE` | `Date` | 日期类型 | +| `10` | `BLOB` | `Buffer` | 二进制数据 | +| `11` | `STRING` | `string` | UTF-8 字符串 | + +处理 `INT64` 类型时,建议在 JavaScript 中使用 `bigint`,避免超出 `number` 安全整数范围后出现精度损失。 + +## 5. 常见问题 + +1. 连接被拒绝:如果出现 `ECONNREFUSED`,请检查 IoTDB 服务是否已启动、RPC 端口是否正确、网络和防火墙是否允许访问。默认端口通常为 `6667`。 + +2. 获取连接超时:如果出现等待可用连接超时,通常说明连接池已被占满。可适当增大 `waitTimeout` 或 `maxPoolSize`,同时检查是否存在手动获取 `Session` 后未调用 `releaseSession(session)` 的情况。 + +3. 查询结果占用内存过高:大结果集查询建议使用 `hasNext()` 和 `next()` 分批读取,并调小 `fetchSize`。仅在结果集较小时使用 `toArray()`。 + +4. 写入性能不稳定:建议优先使用 `insertTablet` 批量写入,并根据数据规模、网络和服务端资源调整每批行数。多节点环境下建议配置 `nodeUrls`,让连接池在多个节点间分配负载。 diff --git a/src/zh/UserGuide/latest-Table/API/Programming-NodeJS-Native-API_apache.md b/src/zh/UserGuide/latest-Table/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..2c731db4e --- /dev/null +++ b/src/zh/UserGuide/latest-Table/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,371 @@ + + +# 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 项目中执行: + +```bash +npm install @iotdb/client +``` + +* **方式二:从源码构建** + +如需使用仓库中的开发版本,可克隆源码并安装依赖: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +Linux、macOS 或 WSL 环境执行: + +```bash +npm run build +``` + +Windows PowerShell 环境执行: + +```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 +``` + +构建完成后,可在业务项目中通过客户端源码目录的绝对路径进行本地安装: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +如使用 TypeScript,无需额外安装类型声明,客户端已内置完整的 TypeScript 类型定义。 + +**注意:请勿使用高版本客户端连接低版本服务。** + +## 2. 核心步骤 + +使用 Node.js 原生接口操作 IoTDB 表模型的三个核心步骤如下: + +1. 创建连接池实例:初始化一个 `TableSessionPool` 对象,配置连接参数、数据库和池大小。 +2. 执行数据库操作:直接通过连接池执行表创建、数据写入或查询等操作。 +3. 关闭连接池资源:程序结束时调用 `tablePool.close()`,释放所有连接。 + +下面的章节用于说明开发的核心流程,并未演示所有参数和接口。如需了解完整能力,可查阅 [`@iotdb/client` 源码](https://github.com/apache/iotdb-client-nodejs/tree/develop/src)及[示例](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples)。 + +### 2.1 创建连接池实例 + +#### 2.1.1 单节点连接 + +```typescript +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` 配置多个节点。连接池会以轮询方式在多个节点间分配连接,并在连接失败时尝试其他可用节点。 + +```typescript +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,并指定证书相关参数。 + +```typescript +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 集群中,客户端支持写入重定向。写入操作发送到非目标节点时,服务端可能返回重定向建议,客户端会缓存目标路由,并在后续写入时优先使用更合适的节点。 + +```typescript +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 创建数据库和表 + +```typescript +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`,每个数组对应一个非时间列。 + +```typescript +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()` 释放服务端查询资源。 + +```typescript +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()` 将全部结果加载到内存: + +```typescript +const dataSet = await tablePool.executeQueryStatement('SHOW TABLES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 关闭连接池 + +```typescript +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 类型 | 说明 | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | 布尔值 | +| `1` | `INT32` | `number` | 32 位整数 | +| `2` | `INT64` | `bigint` | 64 位整数 | +| `3` | `FLOAT` | `number` | 32 位浮点数 | +| `4` | `DOUBLE` | `number` | 64 位浮点数 | +| `5` | `TEXT` | `string` | UTF-8 文本 | +| `8` | `TIMESTAMP` | `Date` | 毫秒精度时间戳 | +| `9` | `DATE` | `Date` | 日期类型 | +| `10` | `BLOB` | `Buffer` | 二进制数据 | +| `11` | `STRING` | `string` | UTF-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`,同时检查是否存在长时间未关闭的查询结果集。 diff --git a/src/zh/UserGuide/latest/API/Programming-NodeJS-Native-API.md b/src/zh/UserGuide/latest/API/Programming-NodeJS-Native-API.md deleted file mode 100644 index ccb096228..000000000 --- a/src/zh/UserGuide/latest/API/Programming-NodeJS-Native-API.md +++ /dev/null @@ -1,201 +0,0 @@ - - - -# Node.js 原生接口 - -IoTDB 使用 Thrift 作为跨语言的 RPC 框架,因此可以通过 Thrift 提供的接口来实现对 IoTDB 的访问。本文档将介绍如何生成可访问 IoTDB 的原生 Node.js 接口。 - - -## 1. 依赖 - - * JDK >= 1.8 - * Node.js >= 16.0.0 - * thrift 0.14.1 - * Linux、Macos 或其他类 unix 系统 - * Windows+bash (下载 IoTDB Go client 需要 git ,通过 WSL、cygwin、Git Bash 任意一种方式均可) - -必须安装 thrift(0.14.1 或更高版本)才能将 thrift 文件编译为 Node.js 代码。下面是官方的安装教程,最终,您应该得到一个 thrift 可执行文件。 - -``` -http://thrift.apache.org/docs/install/ -``` - - -## 2. 编译 thrift 库,生成 Node.js 原生接口 - -1. 在 IoTDB [源代码](https://github.com/apache/iotdb) 文件夹的根目录中找到 pom.xml 文件。 -2. 打开 pom.xml 文件,找到以下内容: - -```xml - - generate-thrift-sources-java - generate-sources - - compile - - - java - ${thrift.exec.absolute.path} - ${basedir}/src/main/thrift - - -``` -3. 参考该设置,在 pom.xml 文件中添加以下内容,用来生成 Node.js 的原生接口: - -```xml - - generate-thrift-sources-nodejs - generate-sources - - compile - - - js:node - ${thrift.exec.absolute.path} - ${basedir}/src/main/thrift - **/common.thrift,**/client.thrift - ${project.build.directory}/generated-sources-nodejs - - -``` - -4. 在 IoTDB [源代码](https://github.com/apache/iotdb) 文件夹的根目录下,运行`mvn clean generate-sources`, - -这个指令将自动删除`iotdb/iotdb-protocol/thrift/target` 和 `iotdb/iotdb-protocol/thrift-commons/target`中的文件,并使用新生成的 thrift 文件重新填充该文件夹。 - -这个文件夹在 git 中会被忽略,并且**永远不应该被推到 git 中!** - -**注意**不要将`iotdb/iotdb-protocol/thrift/target` 和 `iotdb/iotdb-protocol/thrift-commons/target`上传到 git 仓库中 ! - -## 3. 使用 Node.js 原生接口 - -将 `iotdb/iotdb-protocol/thrift/target/generated-sources-nodejs/` 和 `iotdb/iotdb-protocol/thrift-commons/target/generated-sources-nodejs/` 中的文件复制到您的项目中,即可使用。 - - -## 4. 支持的 rpc 接口 - -``` -// 打开一个 session -TSOpenSessionResp openSession(1:TSOpenSessionReq req); - -// 关闭一个 session -TSStatus closeSession(1:TSCloseSessionReq req); - -// 执行一条 SQL 语句 -TSExecuteStatementResp executeStatement(1:TSExecuteStatementReq req); - -// 批量执行 SQL 语句 -TSStatus executeBatchStatement(1:TSExecuteBatchStatementReq req); - -// 执行查询 SQL 语句 -TSExecuteStatementResp executeQueryStatement(1:TSExecuteStatementReq req); - -// 执行插入、删除 SQL 语句 -TSExecuteStatementResp executeUpdateStatement(1:TSExecuteStatementReq req); - -// 向服务器取下一批查询结果 -TSFetchResultsResp fetchResults(1:TSFetchResultsReq req) - -// 获取元数据 -TSFetchMetadataResp fetchMetadata(1:TSFetchMetadataReq req) - -// 取消某次查询操作 -TSStatus cancelOperation(1:TSCancelOperationReq req); - -// 关闭查询操作数据集,释放资源 -TSStatus closeOperation(1:TSCloseOperationReq req); - -// 获取时区信息 -TSGetTimeZoneResp getTimeZone(1:i64 sessionId); - -// 设置时区 -TSStatus setTimeZone(1:TSSetTimeZoneReq req); - -// 获取服务端配置 -ServerProperties getProperties(); - -// 设置 database -TSStatus setStorageGroup(1:i64 sessionId, 2:string storageGroup); - -// 创建时间序列 -TSStatus createTimeseries(1:TSCreateTimeseriesReq req); - -// 创建多条时间序列 -TSStatus createMultiTimeseries(1:TSCreateMultiTimeseriesReq req); - -// 删除时间序列 -TSStatus deleteTimeseries(1:i64 sessionId, 2:list path) - -// 删除 database -TSStatus deleteStorageGroups(1:i64 sessionId, 2:list storageGroup); - -// 按行插入数据 -TSStatus insertRecord(1:TSInsertRecordReq req); - -// 按 String 格式插入一条数据 -TSStatus insertStringRecord(1:TSInsertStringRecordReq req); - -// 按列插入数据 -TSStatus insertTablet(1:TSInsertTabletReq req); - -// 按列批量插入数据 -TSStatus insertTablets(1:TSInsertTabletsReq req); - -// 按行批量插入数据 -TSStatus insertRecords(1:TSInsertRecordsReq req); - -// 按行批量插入同属于某个设备的数据 -TSStatus insertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// 按 String 格式批量按行插入数据 -TSStatus insertStringRecords(1:TSInsertStringRecordsReq req); - -// 测试按列插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertTablet(1:TSInsertTabletReq req); - -// 测试批量按列插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertTablets(1:TSInsertTabletsReq req); - -// 测试按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertRecord(1:TSInsertRecordReq req); - -// 测试按 String 格式按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertStringRecord(1:TSInsertStringRecordReq req); - -// 测试按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertRecords(1:TSInsertRecordsReq req); - -// 测试按行批量插入同属于某个设备的数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertRecordsOfOneDevice(1:TSInsertRecordsOfOneDeviceReq req); - -// 测试按 String 格式批量按行插入数据的延迟,注意:该接口不真实插入数据,只用来测试网络延迟 -TSStatus testInsertStringRecords(1:TSInsertStringRecordsReq req); - -// 删除数据 -TSStatus deleteData(1:TSDeleteDataReq req); - -// 执行原始数据查询 -TSExecuteStatementResp executeRawDataQuery(1:TSRawDataQueryReq req); - -// 向服务器申请一个查询语句 ID -i64 requestStatementId(1:i64 sessionId); -``` diff --git a/src/zh/UserGuide/latest/API/Programming-NodeJS-Native-API_apache.md b/src/zh/UserGuide/latest/API/Programming-NodeJS-Native-API_apache.md new file mode 100644 index 000000000..3200106d9 --- /dev/null +++ b/src/zh/UserGuide/latest/API/Programming-NodeJS-Native-API_apache.md @@ -0,0 +1,374 @@ + + +# Node.js 原生接口 + +Node.js 原生 API 支持通过 `Session` 和 `SessionPool` 两种方式与 IoTDB 树模型进行交互,可执行数据写入、查询、非查询 SQL 以及连接管理等操作。由于 `Session` 非线程安全,生产环境推荐使用 `SessionPool` 编程。在高并发场景下,`SessionPool` 能够统一管理连接资源,并支持多节点负载均衡、故障转移和写入重定向。 + +本文将围绕 `SessionPool` 的使用进行说明,涵盖从环境准备、核心操作步骤到常用接口的完整内容。 + +## 1. 环境准备 + +### 1.1 前置依赖 + +* Node.js >= 14.0.0 +* npm >= 6.0.0 +* IoTDB >= 2.0.11 + +### 1.2 安装方法 + +* **方式一:通过 npm 直接安装(推荐)** + +在 Node.js 项目中执行: + +```bash +npm install @iotdb/client +``` + +* **方式二:从源码构建** + +如需使用仓库中的开发版本,可克隆源码并安装依赖: + +```bash +git clone https://github.com/apache/iotdb-client-nodejs.git +cd iotdb-client-nodejs +git checkout develop +npm ci +``` + +Linux、macOS 或 WSL 环境执行: + +```bash +npm run build +``` + +Windows PowerShell 环境执行: + +```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 +``` + +构建完成后,可在业务项目中通过客户端源码目录的绝对路径进行本地安装: + +```bash +npm install /absolute/path/to/iotdb-client-nodejs +``` + +如使用 TypeScript,无需额外安装类型声明,客户端已内置完整的 TypeScript 类型定义。 + +**注意:请勿使用高版本客户端连接低版本服务。** + +## 2. 核心步骤 + +使用 Node.js 原生接口操作 IoTDB 树模型的三个核心步骤如下: + +1. 创建连接池实例:初始化一个 `SessionPool` 对象,配置连接参数和池大小。 +2. 执行数据库操作:直接通过连接池执行数据写入、查询或非查询 SQL。 +3. 关闭连接池资源:程序结束时调用 `pool.close()`,释放所有连接。 + +下面的章节用于说明开发的核心流程,并未演示所有参数和接口。如需了解完整能力,可查阅 [`@iotdb/client` 源码](https://github.com/apache/iotdb-client-nodejs/tree/develop/src)及[示例](https://github.com/apache/iotdb-client-nodejs/tree/develop/examples)。 + +### 2.1 创建连接池实例 + +#### 2.1.1 单节点连接 + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool('localhost', 6667, { + username: 'root', + password: 'root', + maxPoolSize: 10, + minPoolSize: 2, + maxIdleTime: 60000, + waitTimeout: 60000, +}); + +await pool.init(); +``` + +#### 2.1.2 多节点连接 + +在集群环境下,推荐使用 `nodeUrls` 配置多个节点。连接池会以轮询方式在多个节点间分配连接,并在连接失败时尝试其他可用节点。 + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 15, + minPoolSize: 3, +}); + +await pool.init(); +``` + +也可以使用构建器模式创建连接池配置: + +```typescript +import { SessionPool, PoolConfigBuilder } from '@iotdb/client'; + +const pool = new SessionPool( + new PoolConfigBuilder() + .nodeUrls([ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ]) + .username('root') + .password('root') + .maxPoolSize(15) + .minPoolSize(3) + .build() +); + +await pool.init(); +``` + +连接池参数可按业务并发量调整:`minPoolSize` 建议设置为平均并发负载,`maxPoolSize` 建议设置为峰值并发负载并预留 20% 到 30% 缓冲;`maxIdleTime` 用于清理长期空闲连接,`waitTimeout` 用于控制连接池耗尽时的最大等待时间。生产环境建议监控 `getPoolSize()`、`getAvailableSize()` 和 `getInUseSize()`,根据峰值负载调整连接池大小。 + +#### 2.1.3 SSL/TLS 连接 + +如 IoTDB 服务端启用了 SSL/TLS,可在创建连接池时开启 SSL,并指定证书相关参数。 + +```typescript +import { SessionPool } from '@iotdb/client'; +import * as fs from 'fs'; + +const pool = new SessionPool({ + host: 'localhost', + port: 6667, + username: 'root', + password: 'root', + 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 pool.init(); +``` + +#### 2.1.4 写入重定向 + +在多节点 IoTDB 集群中,客户端支持写入重定向。写入操作发送到非目标节点时,服务端可能返回重定向建议,客户端会缓存设备到节点的映射,并在后续写入同一设备时优先使用目标节点。 + +```typescript +import { SessionPool } from '@iotdb/client'; + +const pool = new SessionPool({ + nodeUrls: [ + '192.168.1.100:6667', + '192.168.1.101:6667', + '192.168.1.102:6667', + ], + username: 'root', + password: 'root', + maxPoolSize: 10, + enableRedirection: true, + redirectCacheTTL: 300000, +}); + +await pool.init(); +``` + +启用重定向后,可减少跨节点转发,提升写入吞吐并降低网络延迟。该能力适用于树模型中的设备级写入场景。 + +### 2.2 数据库操作 + +#### 2.2.1 创建数据库和时间序列 + +```typescript +await pool.executeNonQueryStatement('CREATE DATABASE root.test'); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT, ENCODING=RLE' +); + +await pool.executeNonQueryStatement( + 'CREATE TIMESERIES root.test.device1.humidity WITH DATATYPE=FLOAT, ENCODING=RLE' +); +``` + +#### 2.2.2 写入 Tablet 数据 + +`insertTablet` 支持按设备批量写入多行数据。`values` 为二维数组,按行组织数据:每行对应一个时间戳,与 `timestamps` 顺序一致;每列对应一个测点,与 `measurements` 顺序一致。 + +```typescript +await pool.insertTablet({ + deviceId: 'root.test.device1', + measurements: ['temperature', 'humidity'], + dataTypes: [3, 3], + timestamps: [Date.now(), Date.now() + 1000], + values: [ + [25.5, 60.0], + [26.0, 61.5], + ], +}); +``` + +其中 `dataTypes` 可使用数据类型编码,也可在项目中封装为常量使用。常用类型编码见本文第 4 章。 + +写入数据时建议优先使用 `insertTablet` 批量写入,减少网络往返次数;常见批量大小可从 100 到 1000 行开始压测,再根据数据规模、网络和服务端资源调整。 + +#### 2.2.3 查询数据 + +查询结果通过 `SessionDataSet` 返回,支持分页拉取,适合处理较大的结果集。使用完成后应调用 `close()` 释放服务端查询资源。 + +```typescript +const dataSet = await pool.executeQueryStatement( + 'SELECT temperature, humidity FROM root.test.device1' +); + +while (await dataSet.hasNext()) { + const row = dataSet.next(); + console.log(row.getTimestamp(), row.getFields()); +} + +await dataSet.close(); +``` + +对于小型结果集,也可以使用 `toArray()` 将全部结果加载到内存: + +```typescript +const dataSet = await pool.executeQueryStatement('SHOW DATABASES'); +const rows = await dataSet.toArray(); +console.log(rows); +await dataSet.close(); +``` + +### 2.3 关闭连接池 + +```typescript +await pool.close(); +``` + +建议在应用退出、定时任务结束或服务销毁时统一关闭连接池,避免连接泄漏。 + +## 3. 常用接口 + +### 3.1 SessionPool + +#### 3.1.1 功能描述 + +`SessionPool` 是树模型推荐使用的连接池接口,支持自动会话管理。调用查询、写入或非查询方法时,连接池会自动获取可用 `Session`,执行完成后回收连接。 + +#### 3.1.2 构造方式 + +| 构造方式 | 说明 | +| --- | --- | +| `new SessionPool(hosts, port, config)` | 传统构造方式,适用于单节点或同端口多主机配置 | +| `new SessionPool(config)` | 使用配置对象构造,适合 `nodeUrls` 多节点配置 | +| `new SessionPool(new PoolConfigBuilder().build())` | 使用构建器模式构造,推荐用于参数较多的场景 | + +#### 3.1.3 方法列表 + +| 方法名 | 描述 | +| --- | --- | +| `init()` | 初始化连接池 | +| `close()` | 关闭连接池并释放所有连接 | +| `executeQueryStatement(sql, timeoutMs?)` | 执行查询 SQL,可设置查询超时时间 | +| `executeNonQueryStatement(sql)` | 执行非查询 SQL,例如 DDL 或 DML | +| `insertTablet(tablet)` | 插入 Tablet 数据 | +| `getSession()` | 从连接池中获取一个 `Session`,需要手动归还 | +| `releaseSession(session)` | 将手动获取的 `Session` 释放回连接池 | +| `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 Session + +#### 3.2.1 功能描述 + +`Session` 表示一个独立会话,适用于简单脚本或单线程场景。`Session` 非线程安全,多线程或高并发场景请使用 `SessionPool`。 + +#### 3.2.2 方法列表 + +| 方法名 | 描述 | +| --- | --- | +| `open()` | 打开会话 | +| `close()` | 关闭会话 | +| `executeQueryStatement(sql, timeoutMs?)` | 执行查询 SQL | +| `executeNonQueryStatement(sql)` | 执行非查询 SQL | +| `insertTablet(tablet)` | 插入 Tablet 数据 | +| `isOpen()` | 判断会话是否已打开 | + +## 4. 数据类型 + +插入 Tablet 数据时,需要为每个测点指定对应的数据类型。Node.js 客户端支持的常用类型如下: + +| 类型编码 | 类型名称 | JavaScript 类型 | 说明 | +| --- | --- | --- | --- | +| `0` | `BOOLEAN` | `boolean` | 布尔值 | +| `1` | `INT32` | `number` | 32 位整数 | +| `2` | `INT64` | `bigint` | 64 位整数 | +| `3` | `FLOAT` | `number` | 32 位浮点数 | +| `4` | `DOUBLE` | `number` | 64 位浮点数 | +| `5` | `TEXT` | `string` | UTF-8 文本 | +| `8` | `TIMESTAMP` | `Date` | 毫秒精度时间戳 | +| `9` | `DATE` | `Date` | 日期类型 | +| `10` | `BLOB` | `Buffer` | 二进制数据 | +| `11` | `STRING` | `string` | UTF-8 字符串 | + +处理 `INT64` 类型时,建议在 JavaScript 中使用 `bigint`,避免超出 `number` 安全整数范围后出现精度损失。 + +## 5. 常见问题 + +1. 连接被拒绝:如果出现 `ECONNREFUSED`,请检查 IoTDB 服务是否已启动、RPC 端口是否正确、网络和防火墙是否允许访问。默认端口通常为 `6667`。 + +2. 获取连接超时:如果出现等待可用连接超时,通常说明连接池已被占满。可适当增大 `waitTimeout` 或 `maxPoolSize`,同时检查是否存在手动获取 `Session` 后未调用 `releaseSession(session)` 的情况。 + +3. 查询结果占用内存过高:大结果集查询建议使用 `hasNext()` 和 `next()` 分批读取,并调小 `fetchSize`。仅在结果集较小时使用 `toArray()`。 + +4. 写入性能不稳定:建议优先使用 `insertTablet` 批量写入,并根据数据规模、网络和服务端资源调整每批行数。多节点环境下建议配置 `nodeUrls`,让连接池在多个节点间分配负载。