Version: 1.0.0
Last Updated: 2024
- 1. Introduction
- 2. Installation
- 3. Quick Start
- 4. SessionPool API
- 5. Configuration Builders
- 6. Data Types
- 7. Code Examples
- 8. Best Practices
- 9. Troubleshooting
The Apache IoTDB Node.js Client provides native support for the tree model (timeseries data model), enabling efficient management of time-series data using hierarchical device paths. This guide covers the SessionPool API for tree model operations with connection pooling and high-concurrency support.
The tree model in IoTDB organizes data hierarchically:
- Path-based Organization:
root.{storage_group}.{device}.{measurement} - Timeseries Management: Create and manage individual timeseries with specific data types
- Efficient Batch Insertion: Use
insertTabletfor high-performance batch writes - Flexible Queries: Support for path patterns and wildcard queries
- Connection Pooling: SessionPool for high-concurrency scenarios
- Storage Group: Top-level data organization unit (e.g.,
root.test) - Device: Physical or logical entity that generates data (e.g.,
root.test.device1) - Measurement: Sensor or metric name (e.g.,
temperature,humidity) - Timeseries: Full path with data type (e.g.,
root.test.device1.temperature FLOAT)
npm install @iotdb/clientRequirements:
- Node.js >= 14.0.0
- Apache IoTDB >= 1.0.0
TypeScript:
import{SessionPool,PoolConfigBuilder,TreeTablet,TSDataType}from'@iotdb/client';JavaScript:
const{ SessionPool, PoolConfigBuilder, TreeTablet, TSDataType }=require('@iotdb/client');import{SessionPool,TreeTablet}from'@iotdb/client';asyncfunctionquickStart(){// Create and initialize poolconstpool=newSessionPool('localhost',6667,{username: 'root',password: 'root',maxPoolSize: 10,minPoolSize: 2,});awaitpool.init();try{// Create storage groupawaitpool.executeNonQueryStatement('CREATE DATABASE root.test');// Create timeseriesawaitpool.executeNonQueryStatement('CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT, ENCODING=RLE');// Insert data using TreeTablet class with addRowconsttablet=newTreeTablet('root.test.device1',['temperature'],[3]// FLOAT);tablet.addRow(Date.now(),[25.5]);awaitpool.insertTablet(tablet);// Query dataconstresult=awaitpool.executeQueryStatement('SELECT temperature FROM root.test.device1');console.log('Query result:',result);console.log('Pool size:',pool.getPoolSize());console.log('Available:',pool.getAvailableSize());}finally{awaitpool.close();}}quickStart();SessionPool provides connection pooling for high-concurrency scenarios. It automatically manages multiple sessions, distributes load across nodes, and recycles idle connections.
Key Features:
- Round-robin load balancing across multiple nodes
- Configurable pool size (min/max)
- Automatic idle connection cleanup
- Wait queue for connection requests
- Thread-safe operations
constpool=newSessionPool(['node1','node2','node3'],// Hosts6667,// Port{username: 'root',password: 'root',maxPoolSize: 20,minPoolSize: 5,});constpool=newSessionPool({nodeUrls: ['node1:6667','node2:6668','node3:6669',],username: 'root',password: 'root',maxPoolSize: 20,minPoolSize: 5,});import{PoolConfigBuilder}from'@iotdb/client';constpool=newSessionPool(newPoolConfigBuilder().nodeUrls(['node1:6667','node2:6667','node3:6667']).username('root').password('root').maxPoolSize(20).minPoolSize(5).maxIdleTime(60000).waitTimeout(60000).build());| Option | Type | Default | Description |
|---|---|---|---|
maxPoolSize | number | 10 | Maximum number of sessions in pool |
minPoolSize | number | 1 | Minimum number of sessions maintained |
maxIdleTime | number | 60000 | Max idle time before cleanup (ms) |
waitTimeout | number | 60000 | Max wait time for available session (ms) |
Initializes the connection pool and creates minimum sessions.
Example:
awaitpool.init();Closes all sessions in the pool and releases resources.
Example:
awaitpool.close();The pool automatically acquires and releases sessions for these operations:
Executes a query using an available session from the pool.
Example:
constresult=awaitpool.executeQueryStatement('SELECT * FROM root.test.**');Executes a non-query statement using an available session.
Example:
awaitpool.executeNonQueryStatement('CREATE DATABASE root.test');Inserts data using an available session.
Example:
awaitpool.insertTablet({deviceId: 'root.test.device1',measurements: ['temperature'],dataTypes: [3],timestamps: [Date.now()],values: [[25.5]],});For multiple operations on the same session:
Acquires a session from the pool. Must be released after use.
Example:
constsession=awaitpool.getSession();try{awaitsession.executeNonQueryStatement('CREATE DATABASE root.test');awaitsession.insertTablet({/* data */});constresult=awaitsession.executeQueryStatement('SELECT ...');}finally{pool.releaseSession(session);}Releases a session back to the pool.
Example:
pool.releaseSession(session);Returns the current total number of sessions in the pool.
Returns the number of available (idle) sessions.
Returns the number of sessions currently in use.
Example:
console.log(`Total: ${pool.getPoolSize()}`);console.log(`Available: ${pool.getAvailableSize()}`);console.log(`In Use: ${pool.getInUseSize()}`);Fluent API for building SessionPool configurations.
Available Methods:
host(host: string): thisport(port: number): thisnodeUrls(urls: string[]): thisusername(username: string): thispassword(password: string): thisdatabase(database: string): thistimezone(timezone: string): thisfetchSize(size: number): thisenableSSL(enable: boolean): thissslOptions(options: SSLOptions): thismaxPoolSize(size: number): thisminPoolSize(size: number): thismaxIdleTime(time: number): thiswaitTimeout(timeout: number): thisbuild(): PoolConfig
Example:
constpoolConfig=newPoolConfigBuilder().nodeUrls(['node1:6667','node2:6667']).username('root').password('root').maxPoolSize(20).minPoolSize(5).maxIdleTime(60000).waitTimeout(60000).build();constpool=newSessionPool(poolConfig);The tree model supports all IoTDB data types:
| Code | Type | JavaScript Type | Description |
|---|---|---|---|
| 0 | BOOLEAN | boolean | True or false |
| 1 | INT32 | number | 32-bit signed integer |
| 2 | INT64 | number/string | 64-bit signed integer (use string for large values) |
| 3 | FLOAT | number | 32-bit floating point |
| 4 | DOUBLE | number | 64-bit floating point |
| 5 | TEXT | string | UTF-8 string |
| 8 | TIMESTAMP | number/Date | Milliseconds since epoch |
| 9 | DATE | number/Date | Calendar date as yyyyMMdd integer (e.g. 20240101 for 2024-01-01) |
| 10 | BLOB | Buffer | Binary data |
| 11 | STRING | string | Same as TEXT |
Example with Multiple Types:
awaitpool.insertTablet({deviceId: 'root.test.sensor1',measurements: ['temp','humidity','status','description','reading_time'],dataTypes: [3,4,0,5,8],// FLOAT, DOUBLE, BOOLEAN, TEXT, TIMESTAMPtimestamps: [Date.now()],values: [[25.5,// FLOAT60.123456,// DOUBLEtrue,// BOOLEAN'Normal operation',// TEXTDate.now(),// TIMESTAMP]],});For INT64 values larger than JavaScript's safe integer range (2^53 - 1), use strings:
awaitpool.insertTablet({deviceId: 'root.test.device1',measurements: ['largeCounter'],dataTypes: [2],// INT64timestamps: [Date.now()],values: [['9223372036854775807']],// String for large INT64});import{SessionPool}from'@iotdb/client';asyncfunctioncrudExample(){constpool=newSessionPool('localhost',6667,{username: 'root',password: 'root',maxPoolSize: 10,minPoolSize: 2,});awaitpool.init();try{// CREATEawaitpool.executeNonQueryStatement('CREATE DATABASE root.factory');awaitpool.executeNonQueryStatement('CREATE TIMESERIES root.factory.workshop1.temperature WITH DATATYPE=FLOAT');// INSERTawaitpool.insertTablet({deviceId: 'root.factory.workshop1',measurements: ['temperature'],dataTypes: [3],timestamps: [Date.now()-3000,Date.now()-2000,Date.now()-1000],values: [[25.5],[26.0],[25.8]],});// READconstresult=awaitpool.executeQueryStatement('SELECT temperature FROM root.factory.workshop1');console.log('Temperature readings:',result);// UPDATE (Delete and re-insert)awaitpool.executeNonQueryStatement(`DELETE FROM root.factory.workshop1.temperature WHERE time <= ${Date.now()-2500}`);// DELETEawaitpool.executeNonQueryStatement('DELETE DATABASE root.factory');}finally{awaitpool.close();}}crudExample();import{SessionPool,PoolConfigBuilder}from'@iotdb/client';asyncfunctionmultiNodeExample(){constpool=newSessionPool(newPoolConfigBuilder().nodeUrls(['iotdb-node1:6667','iotdb-node2:6667','iotdb-node3:6667',]).username('root').password('root').maxPoolSize(30).minPoolSize(10).build());awaitpool.init();try{// Simulate concurrent operationsconstoperations=[];for(leti=0;i<100;i++){operations.push(pool.insertTablet({deviceId: `root.test.device${i%10}`,measurements: ['value'],dataTypes: [3],timestamps: [Date.now()],values: [[Math.random()*100]],}));}awaitPromise.all(operations);console.log('All operations completed');// Pool statisticsconsole.log('Pool Statistics:');console.log(` Total Sessions: ${pool.getPoolSize()}`);console.log(` Available: ${pool.getAvailableSize()}`);console.log(` In Use: ${pool.getInUseSize()}`);}finally{awaitpool.close();}}multiNodeExample();asyncfunctiontimeRangeQuery(pool: SessionPool){constnow=Date.now();consthourAgo=now-3600000;constresult=awaitpool.executeQueryStatement(`SELECT temperature, humidity FROM root.test.** WHERE time >= ${hourAgo} AND time <= ${now}`);console.log('Query result:',result);returnresult;}asyncfunctionbatchInsertMultipleDevices(pool: SessionPool){constdevices=['device1','device2','device3'];consttimestamps=[];constnow=Date.now();// Generate timestamps for last 10 minutesfor(leti=0;i<600;i++){timestamps.push(now-(600-i)*1000);}for(constdeviceofdevices){constvalues=timestamps.map(()=>[20+Math.random()*10,// temperature50+Math.random()*30,// humidity]);awaitpool.insertTablet({deviceId: `root.test.${device}`,measurements: ['temperature','humidity'],dataTypes: [3,3],
timestamps,
values,});}console.log(`Inserted ${timestamps.length} records for ${devices.length} devices`);}Always close pool resources:
// SessionPooltry{awaitpool.init();// ... operations}finally{awaitpool.close();}Optimize batch size:
- Use
insertTabletinstead of individual inserts - Batch 100-1000 rows per tablet
- Consider memory vs network trade-offs
Example:
// Good: Batch insertawaitpool.insertTablet({deviceId: 'root.test.device1',measurements: ['temperature'],dataTypes: [3],timestamps: timestamps,// 100-1000 timestampsvalues: values,// 100-1000 values});// Bad: Individual insertsfor(leti=0;i<1000;i++){awaitpool.executeNonQueryStatement(`INSERT INTO root.test.device1(timestamp, temperature) VALUES(${timestamps[i]}, ${values[i]})`);}try{awaitpool.init();awaitpool.executeNonQueryStatement('CREATE DATABASE root.test');}catch(error){if(error.message.includes('already exists')){console.log('Database already exists, continuing...');}else{console.error('Failed to create database:',error);throwerror;}}finally{awaitpool.close();}Guidelines:
- Set
minPoolSizeto average concurrent load - Set
maxPoolSizeto peak load + buffer (20-30%) - Monitor pool statistics in production
- Adjust based on server capacity
Example:
constpool=newSessionPool({nodeUrls: ['localhost:6667'],maxPoolSize: 50,// Peak load: 40 clients + 25% bufferminPoolSize: 20,// Average load: 20 clientsmaxIdleTime: 60000,// Clean up idle after 1 minutewaitTimeout: 30000,// Wait max 30s for available session});Symptoms:
Error: connect ECONNREFUSED 127.0.0.1:6667
Solutions:
- Verify IoTDB is running:
jps | grep IoTDB - Check port configuration in
iotdb-datanode.properties - Verify firewall allows connections
- Test with telnet:
telnet localhost 6667
Symptoms:
Error: Timeout waiting for available session
Solutions:
- Increase
waitTimeoutin pool configuration - Increase
maxPoolSizeif server can handle it - Verify sessions are being released properly
- Check for connection leaks (forgotten
releaseSession())
Symptoms:
FATAL ERROR: Reached heap limit
Solutions:
- Reduce
fetchSizein pool configuration - Process query results in batches
- Increase Node.js heap:
node --max-old-space-size=4096 app.js
Enable debug logging:
// Set environment variableprocess.env.LOG_LEVEL='debug';// Or use logger directlyimport{logger}from'@iotdb/client';logger.setLevel('debug');Check connection status:
console.log('Pool size:',pool.getPoolSize());console.log('Available:',pool.getAvailableSize());console.log('In Use:',pool.getInUseSize());Test query execution time:
conststart=Date.now();constresult=awaitpool.executeQueryStatement('SELECT ...');console.log(`Query took ${Date.now()-start}ms`);- Use connection pooling: For concurrent operations
- Batch inserts: Use insertTablet with 100-1000 rows
- Multi-node setup: Distribute load across nodes
- Monitor resources: Watch CPU, memory, network
- Adjust pool size: Set min/max pool size based on workload
- Documentation: IoTDB Docs
- GitHub Issues: Report bugs
- Mailing List: dev@iotdb.apache.org
See data-types.md for comprehensive data type documentation.
init()- Initialize poolclose()- Close all sessionsexecuteQueryStatement(sql, timeout?)- Execute queryexecuteNonQueryStatement(sql)- Execute DDL/DMLinsertTablet(tablet)- Batch insertgetSession()- Get session from poolreleaseSession(session)- Return session to poolgetPoolSize()- Total sessionsgetAvailableSize()- Available sessionsgetInUseSize()- Active sessions
Version: 1.0.0
Last Updated: January 2024
License: Apache License 2.0