blob: 10173a0dff64f389dd9d1dd91e7490a03b0ae27c [file] [view]
# Apache IoTDB Node.js Client - Tree Model User Guide
> **Version**: 1.0.0
> **Last Updated**: 2024
## Table of Contents
- [1. Introduction](#1-introduction)
- [2. Installation](#2-installation)
- [3. Quick Start](#3-quick-start)
- [4. SessionPool API](#4-sessionpool-api)
- [5. Configuration Builders](#5-configuration-builders)
- [6. Data Types](#6-data-types)
- [7. Code Examples](#7-code-examples)
- [8. Best Practices](#8-best-practices)
- [9. Troubleshooting](#9-troubleshooting)
## 1. Introduction
### 1.1 Overview
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.
### 1.2 Tree Model Features
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 `insertTablet` for high-performance batch writes
- **Flexible Queries**: Support for path patterns and wildcard queries
- **Connection Pooling**: SessionPool for high-concurrency scenarios
### 1.3 Key Concepts
- **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`)
## 2. Installation
### 2.1 Install from npm
```bash
npm install @iotdb/client
```
**Requirements:**
- Node.js >= 14.0.0
- Apache IoTDB >= 1.0.0
### 2.2 Import in Your Project
**TypeScript:**
```typescript
import { SessionPool, PoolConfigBuilder, TreeTablet, TSDataType } from '@iotdb/client';
```
**JavaScript:**
```javascript
const { SessionPool, PoolConfigBuilder, TreeTablet, TSDataType } = require('@iotdb/client');
```
## 3. Quick Start
### 3.1 SessionPool Example
```typescript
import { SessionPool, TreeTablet } from '@iotdb/client';
async function quickStart() {
// Create and initialize pool
const pool = new SessionPool('localhost', 6667, {
username: 'root',
password: 'root',
maxPoolSize: 10,
minPoolSize: 2,
});
await pool.init();
try {
// Create storage group
await pool.executeNonQueryStatement('CREATE DATABASE root.test');
// Create timeseries
await pool.executeNonQueryStatement(
'CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT, ENCODING=RLE'
);
// Insert data using TreeTablet class with addRow
const tablet = new TreeTablet(
'root.test.device1',
['temperature'],
[3] // FLOAT
);
tablet.addRow(Date.now(), [25.5]);
await pool.insertTablet(tablet);
// Query data
const result = await pool.executeQueryStatement(
'SELECT temperature FROM root.test.device1'
);
console.log('Query result:', result);
console.log('Pool size:', pool.getPoolSize());
console.log('Available:', pool.getAvailableSize());
} finally {
await pool.close();
}
}
quickStart();
```
## 4. SessionPool API
### 4.1 Overview
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
### 4.2 Constructor
#### Option 1: Traditional API (Same Port)
```typescript
const pool = new SessionPool(
['node1', 'node2', 'node3'], // Hosts
6667, // Port
{
username: 'root',
password: 'root',
maxPoolSize: 20,
minPoolSize: 5,
}
);
```
#### Option 2: Using nodeUrls (Different Ports)
```typescript
const pool = new SessionPool({
nodeUrls: [
'node1:6667',
'node2:6668',
'node3:6669',
],
username: 'root',
password: 'root',
maxPoolSize: 20,
minPoolSize: 5,
});
```
#### Option 3: Using Builder Pattern (Recommended)
```typescript
import { PoolConfigBuilder } from '@iotdb/client';
const pool = new SessionPool(
new PoolConfigBuilder()
.nodeUrls(['node1:6667', 'node2:6667', 'node3:6667'])
.username('root')
.password('root')
.maxPoolSize(20)
.minPoolSize(5)
.maxIdleTime(60000)
.waitTimeout(60000)
.build()
);
```
### 4.3 Pool Configuration Options
| 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) |
### 4.4 Methods
#### 4.4.1 Pool Management
##### `async init(): Promise<void>`
Initializes the connection pool and creates minimum sessions.
**Example:**
```typescript
await pool.init();
```
##### `async close(): Promise<void>`
Closes all sessions in the pool and releases resources.
**Example:**
```typescript
await pool.close();
```
#### 4.4.2 Automatic Session Management
The pool automatically acquires and releases sessions for these operations:
##### `async executeQueryStatement(sql: string, timeoutMs?: number): Promise<QueryResult>`
Executes a query using an available session from the pool.
**Example:**
```typescript
const result = await pool.executeQueryStatement('SELECT * FROM root.test.**');
```
##### `async executeNonQueryStatement(sql: string): Promise<void>`
Executes a non-query statement using an available session.
**Example:**
```typescript
await pool.executeNonQueryStatement('CREATE DATABASE root.test');
```
##### `async insertTablet(tablet: Tablet): Promise<void>`
Inserts data using an available session.
**Example:**
```typescript
await pool.insertTablet({
deviceId: 'root.test.device1',
measurements: ['temperature'],
dataTypes: [3],
timestamps: [Date.now()],
values: [[25.5]],
});
```
#### 4.4.3 Explicit Session Management
For multiple operations on the same session:
##### `async getSession(): Promise<Session>`
Acquires a session from the pool. **Must** be released after use.
**Example:**
```typescript
const session = await pool.getSession();
try {
await session.executeNonQueryStatement('CREATE DATABASE root.test');
await session.insertTablet({ /* data */ });
const result = await session.executeQueryStatement('SELECT ...');
} finally {
pool.releaseSession(session);
}
```
##### `releaseSession(session: Session): void`
Releases a session back to the pool.
**Example:**
```typescript
pool.releaseSession(session);
```
#### 4.4.4 Pool Statistics
##### `getPoolSize(): number`
Returns the current total number of sessions in the pool.
##### `getAvailableSize(): number`
Returns the number of available (idle) sessions.
##### `getInUseSize(): number`
Returns the number of sessions currently in use.
**Example:**
```typescript
console.log(`Total: ${pool.getPoolSize()}`);
console.log(`Available: ${pool.getAvailableSize()}`);
console.log(`In Use: ${pool.getInUseSize()}`);
```
## 5. Configuration Builders
### 5.1 PoolConfigBuilder
Fluent API for building SessionPool configurations.
**Available Methods:**
- `host(host: string): this`
- `port(port: number): this`
- `nodeUrls(urls: string[]): this`
- `username(username: string): this`
- `password(password: string): this`
- `database(database: string): this`
- `timezone(timezone: string): this`
- `fetchSize(size: number): this`
- `enableSSL(enable: boolean): this`
- `sslOptions(options: SSLOptions): this`
- `maxPoolSize(size: number): this`
- `minPoolSize(size: number): this`
- `maxIdleTime(time: number): this`
- `waitTimeout(timeout: number): this`
- `build(): PoolConfig`
**Example:**
```typescript
const poolConfig = new PoolConfigBuilder()
.nodeUrls(['node1:6667', 'node2:6667'])
.username('root')
.password('root')
.maxPoolSize(20)
.minPoolSize(5)
.maxIdleTime(60000)
.waitTimeout(60000)
.build();
const pool = new SessionPool(poolConfig);
```
## 6. Data Types
### 6.1 Supported Data Types
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 | Days since epoch |
| 10 | BLOB | Buffer | Binary data |
| 11 | STRING | string | Same as TEXT |
### 6.2 Using Data Types in insertTablet
**Example with Multiple Types:**
```typescript
await pool.insertTablet({
deviceId: 'root.test.sensor1',
measurements: ['temp', 'humidity', 'status', 'description', 'reading_time'],
dataTypes: [3, 4, 0, 5, 8], // FLOAT, DOUBLE, BOOLEAN, TEXT, TIMESTAMP
timestamps: [Date.now()],
values: [[
25.5, // FLOAT
60.123456, // DOUBLE
true, // BOOLEAN
'Normal operation', // TEXT
Date.now(), // TIMESTAMP
]],
});
```
### 6.3 Handling INT64
For INT64 values larger than JavaScript's safe integer range (2^53 - 1), use strings:
```typescript
await pool.insertTablet({
deviceId: 'root.test.device1',
measurements: ['largeCounter'],
dataTypes: [2], // INT64
timestamps: [Date.now()],
values: [['9223372036854775807']], // String for large INT64
});
```
## 7. Code Examples
### 7.1 Complete CRUD Example
```typescript
import { SessionPool } from '@iotdb/client';
async function crudExample() {
const pool = new SessionPool('localhost', 6667, {
username: 'root',
password: 'root',
maxPoolSize: 10,
minPoolSize: 2,
});
await pool.init();
try {
// CREATE
await pool.executeNonQueryStatement('CREATE DATABASE root.factory');
await pool.executeNonQueryStatement(
'CREATE TIMESERIES root.factory.workshop1.temperature WITH DATATYPE=FLOAT'
);
// INSERT
await pool.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]],
});
// READ
const result = await pool.executeQueryStatement(
'SELECT temperature FROM root.factory.workshop1'
);
console.log('Temperature readings:', result);
// UPDATE (Delete and re-insert)
await pool.executeNonQueryStatement(
`DELETE FROM root.factory.workshop1.temperature WHERE time <= ${Date.now() - 2500}`
);
// DELETE
await pool.executeNonQueryStatement('DELETE DATABASE root.factory');
} finally {
await pool.close();
}
}
crudExample();
```
### 7.2 Multi-Node SessionPool Example
```typescript
import { SessionPool, PoolConfigBuilder } from '@iotdb/client';
async function multiNodeExample() {
const pool = new SessionPool(
new PoolConfigBuilder()
.nodeUrls([
'iotdb-node1:6667',
'iotdb-node2:6667',
'iotdb-node3:6667',
])
.username('root')
.password('root')
.maxPoolSize(30)
.minPoolSize(10)
.build()
);
await pool.init();
try {
// Simulate concurrent operations
const operations = [];
for (let i = 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]],
})
);
}
await Promise.all(operations);
console.log('All operations completed');
// Pool statistics
console.log('Pool Statistics:');
console.log(` Total Sessions: ${pool.getPoolSize()}`);
console.log(` Available: ${pool.getAvailableSize()}`);
console.log(` In Use: ${pool.getInUseSize()}`);
} finally {
await pool.close();
}
}
multiNodeExample();
```
### 7.3 Time Range Query Example
```typescript
async function timeRangeQuery(pool: SessionPool) {
const now = Date.now();
const hourAgo = now - 3600000;
const result = await pool.executeQueryStatement(
`SELECT temperature, humidity FROM root.test.** WHERE time >= ${hourAgo} AND time <= ${now}`
);
console.log('Query result:', result);
return result;
}
```
### 7.4 Batch Insert with Multiple Devices
```typescript
async function batchInsertMultipleDevices(pool: SessionPool) {
const devices = ['device1', 'device2', 'device3'];
const timestamps = [];
const now = Date.now();
// Generate timestamps for last 10 minutes
for (let i = 0; i < 600; i++) {
timestamps.push(now - (600 - i) * 1000);
}
for (const device of devices) {
const values = timestamps.map(() => [
20 + Math.random() * 10, // temperature
50 + Math.random() * 30, // humidity
]);
await pool.insertTablet({
deviceId: `root.test.${device}`,
measurements: ['temperature', 'humidity'],
dataTypes: [3, 3],
timestamps,
values,
});
}
console.log(`Inserted ${timestamps.length} records for ${devices.length} devices`);
}
```
## 8. Best Practices
### 8.1 Resource Management
**Always close pool resources:**
```typescript
// SessionPool
try {
await pool.init();
// ... operations
} finally {
await pool.close();
}
```
### 8.2 Batch Insertion
**Optimize batch size:**
- Use `insertTablet` instead of individual inserts
- Batch 100-1000 rows per tablet
- Consider memory vs network trade-offs
**Example:**
```typescript
// Good: Batch insert
await pool.insertTablet({
deviceId: 'root.test.device1',
measurements: ['temperature'],
dataTypes: [3],
timestamps: timestamps, // 100-1000 timestamps
values: values, // 100-1000 values
});
// Bad: Individual inserts
for (let i = 0; i < 1000; i++) {
await pool.executeNonQueryStatement(
`INSERT INTO root.test.device1(timestamp, temperature) VALUES(${timestamps[i]}, ${values[i]})`
);
}
```
### 8.3 Error Handling
```typescript
try {
await pool.init();
await pool.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);
throw error;
}
} finally {
await pool.close();
}
```
### 8.4 Connection Pool Sizing
**Guidelines:**
- Set `minPoolSize` to average concurrent load
- Set `maxPoolSize` to peak load + buffer (20-30%)
- Monitor pool statistics in production
- Adjust based on server capacity
**Example:**
```typescript
const pool = new SessionPool({
nodeUrls: ['localhost:6667'],
maxPoolSize: 50, // Peak load: 40 clients + 25% buffer
minPoolSize: 20, // Average load: 20 clients
maxIdleTime: 60000, // Clean up idle after 1 minute
waitTimeout: 30000, // Wait max 30s for available session
});
```
## 9. Troubleshooting
### 9.1 Common Issues
#### Connection Refused
**Symptoms:**
```
Error: connect ECONNREFUSED 127.0.0.1:6667
```
**Solutions:**
1. Verify IoTDB is running: `jps | grep IoTDB`
2. Check port configuration in `iotdb-datanode.properties`
3. Verify firewall allows connections
4. Test with telnet: `telnet localhost 6667`
#### Pool Timeout
**Symptoms:**
```
Error: Timeout waiting for available session
```
**Solutions:**
1. Increase `waitTimeout` in pool configuration
2. Increase `maxPoolSize` if server can handle it
3. Verify sessions are being released properly
4. Check for connection leaks (forgotten `releaseSession()`)
#### Out of Memory
**Symptoms:**
```
FATAL ERROR: Reached heap limit
```
**Solutions:**
1. Reduce `fetchSize` in pool configuration
2. Process query results in batches
3. Increase Node.js heap: `node --max-old-space-size=4096 app.js`
### 9.2 Debugging Tips
**Enable debug logging:**
```typescript
// Set environment variable
process.env.LOG_LEVEL = 'debug';
// Or use logger directly
import { logger } from '@iotdb/client';
logger.setLevel('debug');
```
**Check connection status:**
```typescript
console.log('Pool size:', pool.getPoolSize());
console.log('Available:', pool.getAvailableSize());
console.log('In Use:', pool.getInUseSize());
```
**Test query execution time:**
```typescript
const start = Date.now();
const result = await pool.executeQueryStatement('SELECT ...');
console.log(`Query took ${Date.now() - start}ms`);
```
### 9.3 Performance Optimization
1. **Use connection pooling**: For concurrent operations
2. **Batch inserts**: Use insertTablet with 100-1000 rows
3. **Multi-node setup**: Distribute load across nodes
4. **Monitor resources**: Watch CPU, memory, network
5. **Adjust pool size**: Set min/max pool size based on workload
### 9.4 Getting Help
- **Documentation**: [IoTDB Docs](https://iotdb.apache.org/)
- **GitHub Issues**: [Report bugs](https://github.com/CritasWang/@iotdb/client/issues)
- **Mailing List**: dev@iotdb.apache.org
## Appendix A: Complete Type Reference
See [data-types.md](data-types.md) for comprehensive data type documentation.
## Appendix B: API Quick Reference
### SessionPool Methods
- `init()` - Initialize pool
- `close()` - Close all sessions
- `executeQueryStatement(sql, timeout?)` - Execute query
- `executeNonQueryStatement(sql)` - Execute DDL/DML
- `insertTablet(tablet)` - Batch insert
- `getSession()` - Get session from pool
- `releaseSession(session)` - Return session to pool
- `getPoolSize()` - Total sessions
- `getAvailableSize()` - Available sessions
- `getInUseSize()` - Active sessions
---
**Version**: 1.0.0
**Last Updated**: January 2024
**License**: Apache License 2.0