blob: 107e8a60864c9947d0b56e375b3e79e6b4e0b362 [file] [view]
# Apache IoTDB Node.js Client - Table 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. TableSessionPool API](#4-tablesessionpool-api)
- [5. Configuration Builder](#5-configuration-builder)
- [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 table model (relational data model), enabling efficient management of structured data using SQL-like table operations. This guide covers the TableSessionPool API for table model operations.
### 1.2 Table Model Features
The table model in IoTDB organizes data in a relational format:
- **Database-based Organization**: Create and manage databases containing multiple tables
- **Table Schema**: Define tables with tags, attributes, and fields
- **SQL Operations**: Use familiar SQL syntax for queries and data manipulation
- **Connection Pooling**: Built-in pool for high-concurrency scenarios
- **Automatic Context**: Database context management with `USE DATABASE`
### 1.3 Key Concepts
- **Database**: Logical grouping of related tables
- **Table**: Schema definition with columns and column categories
- **Tags**: Identifiers for time series (indexed, used in WHERE clauses)
- **Attributes**: Metadata for time series (not indexed)
- **Fields**: Actual measurement values
### 1.4 Table Model vs Tree Model
| Aspect | Table Model | Tree Model |
|--------|-------------|------------|
| Organization | Relational tables | Hierarchical paths |
| Schema | Explicit table schema | Timeseries definitions |
| Query Language | Standard SQL | IoTDB SQL with paths |
| Use Case | Structured, relational data | Hierarchical IoT data |
| Data Model | Tags + Attributes + Fields | Device + Measurements |
## 2. Installation
### 2.1 Install from npm
```bash
npm install @iotdb/client
```
**Requirements:**
- Node.js >= 14.0.0
- Apache IoTDB >= 1.0.0 (with table model support)
### 2.2 Import in Your Project
**TypeScript:**
```typescript
import { TableSessionPool, PoolConfigBuilder, TableTablet, ColumnCategory, TSDataType } from '@iotdb/client';
```
**JavaScript:**
```javascript
const { TableSessionPool, PoolConfigBuilder, TableTablet, ColumnCategory, TSDataType } = require('@iotdb/client');
```
## 3. Quick Start
### 3.1 Basic TableSessionPool Example
```typescript
import { TableSessionPool, TableTablet, ColumnCategory } from '@iotdb/client';
async function quickStart() {
// Create and initialize table session pool
const pool = new TableSessionPool('localhost', 6667, {
username: 'root',
password: 'root',
database: 'test_db', // Optional: set default database
maxPoolSize: 10,
minPoolSize: 2,
});
await pool.open();
try {
// Create database
await pool.executeNonQueryStatement('CREATE DATABASE test_db');
// Use database
await pool.executeNonQueryStatement('USE test_db');
// Create table
await pool.executeNonQueryStatement(`
CREATE TABLE sensor_data (
region_id STRING TAG,
device_id STRING TAG,
model STRING ATTRIBUTE,
temperature FLOAT FIELD,
humidity DOUBLE FIELD
) WITH (TTL=3600000)
`);
// Insert data using TableTablet class with addRow
const tablet = new TableTablet(
'sensor_data',
['region_id', 'device_id', 'model', 'temperature', 'humidity'],
[5, 5, 5, 3, 4], // STRING, STRING, STRING, FLOAT, DOUBLE
[ColumnCategory.TAG, ColumnCategory.TAG, ColumnCategory.ATTRIBUTE, ColumnCategory.FIELD, ColumnCategory.FIELD]
);
tablet.addRow(Date.now(), ['region1', 'device001', 'ModelA', 25.5, 60.0]);
await pool.insertTablet(tablet);
// Query data
const dataSet = await pool.executeQueryStatement(`
SELECT * FROM sensor_data
WHERE region_id = 'region1' AND device_id = 'device001'
`);
while (await dataSet.hasNext()) {
const row = dataSet.next();
console.log(`Temperature: ${row.getFloat('temperature')}°C, Humidity: ${row.getDouble('humidity')}%`);
}
await dataSet.close();
} finally {
await pool.close();
}
}
quickStart();
```
### 3.2 With Database Context
```typescript
async function withDatabaseContext() {
// Create pool with database pre-configured
const pool = new TableSessionPool('localhost', 6667, {
username: 'root',
password: 'root',
database: 'production_db', // Automatically executes USE DATABASE
maxPoolSize: 20,
});
await pool.open();
try {
// No need for explicit USE DATABASE
// Already in 'production_db' context
const dataSet = await pool.executeQueryStatement('SHOW TABLES');
while (await dataSet.hasNext()) {
const row = dataSet.next();
console.log('Table:', row.getFields());
}
await dataSet.close();
} finally {
await pool.close();
}
}
```
## 4. TableSessionPool API
### 4.1 Overview
TableSessionPool is a specialized connection pool for table model operations. It extends the base SessionPool functionality with table-specific features and automatic database context management.
**Key Features:**
- Same connection pooling as SessionPool
- Automatic `USE DATABASE` when configured with database
- Table-specific insertTablet with column categories
- SQL-based operations
- Round-robin load balancing
### 4.2 Constructor
#### Option 1: Traditional API (Same Port)
```typescript
const pool = new TableSessionPool(
'localhost', // Host
6667, // Port
{
username: 'root',
password: 'root',
database: 'my_database', // Optional
maxPoolSize: 20,
minPoolSize: 5,
}
);
```
#### Option 2: Using nodeUrls (Different Ports)
```typescript
const pool = new TableSessionPool({
nodeUrls: [
'node1:6667',
'node2:6668',
'node3:6669',
],
username: 'root',
password: 'root',
database: 'my_database',
maxPoolSize: 20,
minPoolSize: 5,
});
```
#### Option 3: Using Builder Pattern (Recommended)
```typescript
import { PoolConfigBuilder } from '@iotdb/client';
const pool = new TableSessionPool(
new PoolConfigBuilder()
.nodeUrls(['node1:6667', 'node2:6667'])
.username('root')
.password('root')
.database('my_database')
.maxPoolSize(20)
.minPoolSize(5)
.maxIdleTime(60000)
.waitTimeout(60000)
.build()
);
```
### 4.3 Configuration Options
All SessionPool options plus:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `database` | string | `undefined` | Default database for table operations |
### 4.4 Methods
#### 4.4.1 Connection Management
##### `async open(enableRpcCompression?: boolean): Promise<void>`
Opens the connection pool. Optionally enables RPC compression.
**Parameters:**
- `enableRpcCompression`: Enable RPC compression (default: false)
**Example:**
```typescript
// Open without compression
await pool.open();
// Open with compression
await pool.open(true);
```
##### `async close(): Promise<void>`
Closes all sessions in the pool.
**Example:**
```typescript
await pool.close();
```
#### 4.4.2 Query Operations
##### `async executeQueryStatement(sql: string, timeoutMs?: number): Promise<SessionDataSet>`
Executes a SQL query statement.
**Parameters:**
- `sql`: SQL query statement
- `timeoutMs`: Query timeout in milliseconds (default: 60000)
**Returns:** SessionDataSet for iterating results
**Example:**
```typescript
const dataSet = await pool.executeQueryStatement(`
SELECT temperature, humidity
FROM sensor_data
WHERE region_id = 'region1'
LIMIT 100
`);
while (await dataSet.hasNext()) {
const row = dataSet.next();
console.log(row.getTimestamp(), row.getFloat('temperature'));
}
await dataSet.close();
```
#### 4.4.3 Non-Query Operations
##### `async executeNonQueryStatement(sql: string): Promise<void>`
Executes DDL or DML statements.
**Parameters:**
- `sql`: SQL statement
**Example:**
```typescript
// Create database
await pool.executeNonQueryStatement('CREATE DATABASE my_db');
// Use database
await pool.executeNonQueryStatement('USE my_db');
// Create table
await pool.executeNonQueryStatement(`
CREATE TABLE devices (
device_id STRING TAG,
location STRING ATTRIBUTE,
value FLOAT FIELD
)
`);
// Drop table
await pool.executeNonQueryStatement('DROP TABLE devices');
// Drop database
await pool.executeNonQueryStatement('DROP DATABASE my_db');
```
#### 4.4.4 Data Insertion
##### `async insertTablet(tablet: TableTablet | ITableTablet): Promise<void>`
Inserts data into a table using tablet format.
**Parameters:**
- `tablet`: TableTablet object or plain object containing table data
**TableTablet Interface (for plain objects):**
```typescript
interface ITableTablet {
tableName: string; // Table name
columnNames: string[]; // Column names
columnTypes: number[]; // Data type codes (TSDataType)
columnCategories: ColumnCategory[]; // Column categories
timestamps: number[]; // Timestamps in milliseconds
values: any[][]; // 2D array: [rows][columns]
}
```
**ColumnCategory Enum:**
```typescript
enum ColumnCategory {
TAG = 0, // Tag column - indexed for WHERE clause filtering (e.g., device_id, region_id)
FIELD = 2, // Field column - measurement values (e.g., temperature, humidity)
ATTRIBUTE = 1, // Attribute column - metadata not indexed (e.g., model, firmware_version)
TIME = 3, // Time column (reserved for internal use only)
}
```
**Column Categories Explained:**
- `TAG` (0) - Indexed columns used for filtering in WHERE clauses (e.g., device_id, region_id)
- `FIELD` (2) - Measurement values (e.g., temperature, humidity)
- `ATTRIBUTE` (1) - Metadata not used for filtering (e.g., device_model, firmware_version)
- `TIME` (3) - Reserved for internal use. **Do not use** in columnCategories array - timestamps are handled separately via the timestamps array
**TableTablet Class (with helper methods - recommended):**
```typescript
import { TableTablet, ColumnCategory, TSDataType } from '@iotdb/client';
// Create a tablet
const tablet = new TableTablet(
'sensor_data',
['region_id', 'device_id', 'model', 'temperature', 'humidity'],
[TSDataType.TEXT, TSDataType.TEXT, TSDataType.TEXT, TSDataType.FLOAT, TSDataType.DOUBLE],
[ColumnCategory.TAG, ColumnCategory.TAG, ColumnCategory.ATTRIBUTE, ColumnCategory.FIELD, ColumnCategory.FIELD]
);
// Add rows one at a time using addRow method
tablet.addRow(Date.now(), ['region1', 'device001', 'ModelA', 25.5, 60.0]);
tablet.addRow(Date.now() + 1000, ['region1', 'device001', 'ModelA', 26.0, 61.5]);
tablet.addRow(Date.now() + 2000, ['region1', 'device002', 'ModelB', 24.8, 58.5]);
// Insert the tablet
await pool.insertTablet(tablet);
```
**Alternative: Plain object approach (still supported):**
```typescript
import { ColumnCategory, TSDataType } from '@iotdb/client';
await pool.insertTablet({
tableName: 'sensor_data',
columnNames: ['region_id', 'device_id', 'model', 'temperature', 'humidity'],
columnTypes: [TSDataType.TEXT, TSDataType.TEXT, TSDataType.TEXT, TSDataType.FLOAT, TSDataType.DOUBLE],
columnCategories: [
ColumnCategory.TAG, // region_id - indexed tag
ColumnCategory.TAG, // device_id - indexed tag
ColumnCategory.ATTRIBUTE, // model - metadata
ColumnCategory.FIELD, // temperature - measurement
ColumnCategory.FIELD, // humidity - measurement
],
timestamps: [
Date.now(),
Date.now() + 1000,
Date.now() + 2000,
],
values: [
['region1', 'device001', 'ModelA', 25.5, 60.0],
['region1', 'device001', 'ModelA', 26.0, 61.5],
['region1', 'device002', 'ModelB', 24.8, 58.5],
],
});
```
**Example with numeric values (also supported):**
```typescript
await pool.insertTablet({
tableName: 'sensor_data',
columnNames: ['region_id', 'device_id', 'model', 'temperature', 'humidity'],
columnTypes: [5, 5, 5, 3, 4], // TEXT, TEXT, TEXT, FLOAT, DOUBLE
columnCategories: [0, 0, 1, 2, 2], // TAG, TAG, ATTRIBUTE, FIELD, FIELD
timestamps: [Date.now()],
values: [['region1', 'device001', 'ModelA', 25.5, 60.0]],
});
```
**Benefits of TableTablet class:**
- **Convenient**: `addRow()` method simplifies adding data row-by-row
- **Type-safe**: Constructor validates parameter lengths
- **Validated**: Automatic checking that values match columns count
- **Streaming-friendly**: Easy to add rows as data arrives
## 5. Configuration Builder
### 5.1 PoolConfigBuilder for Table Model
The PoolConfigBuilder is used to create TableSessionPool 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` - **Important for table model**
- `timezone(timezone: string): this`
- `fetchSize(size: number): this`
- `maxPoolSize(size: number): this`
- `minPoolSize(size: number): this`
- `maxIdleTime(time: number): this`
- `waitTimeout(timeout: number): this`
- `enableSSL(enable: boolean): this`
- `sslOptions(options: SSLOptions): this`
- `build(): PoolConfig`
**Example:**
```typescript
const config = new PoolConfigBuilder()
.nodeUrls(['iotdb1:6667', 'iotdb2:6667', 'iotdb3:6667'])
.username('root')
.password('root')
.database('production_db')
.fetchSize(2048)
.maxPoolSize(30)
.minPoolSize(10)
.maxIdleTime(60000)
.waitTimeout(60000)
.build();
const pool = new TableSessionPool(config);
await pool.open();
```
## 6. Data Types
### 6.1 Supported Data Types
The table model supports all IoTDB data types:
| Code | Type | JavaScript Type | Usage in Table Model |
|------|------|-----------------|---------------------|
| 0 | BOOLEAN | boolean | Tags, Attributes, Fields |
| 1 | INT32 | number | Tags, Attributes, Fields |
| 2 | INT64 | number/string | Tags, Attributes, Fields |
| 3 | FLOAT | number | Attributes, Fields |
| 4 | DOUBLE | number | Attributes, Fields |
| 5 | TEXT | string | Tags, Attributes, Fields |
| 8 | TIMESTAMP | number/Date | Fields |
| 9 | DATE | number/Date | Fields |
| 10 | BLOB | Buffer | Fields |
| 11 | STRING | string | Tags, Attributes, Fields |
### 6.2 Column Categories
| Code | Category | Purpose | Indexed | Usage |
|------|----------|---------|---------|-------|
| 0 | TAG | Identifiers | Yes | Use in WHERE clauses for filtering |
| 1 | ATTRIBUTE | Metadata | No | Descriptive information |
| 2 | FIELD | Measurements | No | Actual sensor/measurement values |
### 6.3 Using Data Types in insertTablet
**Example with Mixed Types:**
```typescript
await pool.insertTablet({
tableName: 'equipment_metrics',
columnNames: [
'factory_id', // TAG
'equipment_id', // TAG
'manufacturer', // ATTRIBUTE
'model', // ATTRIBUTE
'temperature', // FIELD
'pressure', // FIELD
'is_active', // FIELD
'last_check', // FIELD
],
columnTypes: [5, 5, 5, 5, 3, 4, 0, 8], // STRING, STRING, STRING, STRING, FLOAT, DOUBLE, BOOLEAN, TIMESTAMP
columnCategories: [0, 0, 1, 1, 2, 2, 2, 2], // TAG, TAG, ATTR, ATTR, FIELD, FIELD, FIELD, FIELD
timestamps: [Date.now()],
values: [[
'factory01',
'equip123',
'ManufacturerA',
'ModelX',
75.5,
101.325,
true,
Date.now(),
]],
});
```
## 7. Code Examples
### 7.1 Complete Database and Table Setup
```typescript
import { TableSessionPool, PoolConfigBuilder } from '@iotdb/client';
async function setupDatabase() {
const pool = new TableSessionPool(
new PoolConfigBuilder()
.host('localhost')
.port(6667)
.username('root')
.password('root')
.maxPoolSize(10)
.build()
);
await pool.open();
try {
// Create database
await pool.executeNonQueryStatement('CREATE DATABASE iot_platform');
// Use the database
await pool.executeNonQueryStatement('USE iot_platform');
// Create table with TTL
await pool.executeNonQueryStatement(`
CREATE TABLE sensor_readings (
region_id STRING TAG,
building_id STRING TAG,
floor INT32 TAG,
device_id STRING TAG,
device_type STRING ATTRIBUTE,
location STRING ATTRIBUTE,
temperature FLOAT FIELD,
humidity FLOAT FIELD,
co2_level INT32 FIELD,
timestamp TIMESTAMP FIELD
) WITH (TTL=7776000000)
`);
console.log('Database and table created successfully');
// Show tables
const dataSet = await pool.executeQueryStatement('SHOW TABLES');
console.log('Tables in database:');
while (await dataSet.hasNext()) {
console.log(dataSet.next().getFields());
}
await dataSet.close();
} finally {
await pool.close();
}
}
setupDatabase();
```
### 7.2 Batch Insert Multiple Records
```typescript
async function batchInsert(pool: TableSessionPool) {
const regionIds = ['north', 'south', 'east', 'west'];
const deviceIds = ['dev001', 'dev002', 'dev003'];
const timestamps = [];
const values = [];
const now = Date.now();
// Generate 100 records
for (let i = 0; i < 100; i++) {
timestamps.push(now + i * 1000);
const region = regionIds[i % regionIds.length];
const device = deviceIds[i % deviceIds.length];
values.push([
region, // region_id (TAG)
device, // device_id (TAG)
'SensorModelA', // model (ATTRIBUTE)
20 + Math.random() * 10, // temperature (FIELD)
50 + Math.random() * 30, // humidity (FIELD)
]);
}
await pool.insertTablet({
tableName: 'sensor_readings',
columnNames: ['region_id', 'device_id', 'model', 'temperature', 'humidity'],
columnTypes: [5, 5, 5, 3, 3],
columnCategories: [0, 0, 1, 2, 2],
timestamps,
values,
});
console.log(`Inserted ${timestamps.length} records`);
}
```
### 7.3 Query with Filtering
```typescript
async function queryWithFilters(pool: TableSessionPool) {
// Query by TAG (indexed, efficient)
const dataSet = await pool.executeQueryStatement(`
SELECT
device_id,
temperature,
humidity,
timestamp
FROM sensor_readings
WHERE
region_id = 'north'
AND device_id IN ('dev001', 'dev002')
AND temperature > 25.0
ORDER BY timestamp DESC
LIMIT 100
`);
const results = [];
while (await dataSet.hasNext()) {
const row = dataSet.next();
results.push({
deviceId: row.getString('device_id'),
temperature: row.getFloat('temperature'),
humidity: row.getFloat('humidity'),
timestamp: new Date(row.getTimestamp()),
});
}
await dataSet.close();
console.log(`Found ${results.length} matching records`);
return results;
}
```
### 7.4 Aggregation Queries
```typescript
async function aggregationQuery(pool: TableSessionPool) {
const dataSet = await pool.executeQueryStatement(`
SELECT
region_id,
device_id,
AVG(temperature) as avg_temp,
MAX(temperature) as max_temp,
MIN(temperature) as min_temp,
COUNT(*) as record_count
FROM sensor_readings
WHERE timestamp >= ${Date.now() - 3600000}
GROUP BY region_id, device_id
`);
console.log('Aggregation Results:');
while (await dataSet.hasNext()) {
const row = dataSet.next();
console.log(`Region: ${row.getString('region_id')}, Device: ${row.getString('device_id')}`);
console.log(` Avg Temp: ${row.getFloat('avg_temp').toFixed(2)}°C`);
console.log(` Max Temp: ${row.getFloat('max_temp').toFixed(2)}°C`);
console.log(` Min Temp: ${row.getFloat('min_temp').toFixed(2)}°C`);
console.log(` Records: ${row.getInt('record_count')}`);
}
await dataSet.close();
}
```
### 7.5 Multi-Database Operations
```typescript
async function multiDatabaseOps(pool: TableSessionPool) {
await pool.open();
try {
// Create multiple databases
await pool.executeNonQueryStatement('CREATE DATABASE production');
await pool.executeNonQueryStatement('CREATE DATABASE staging');
// Work with production database
await pool.executeNonQueryStatement('USE production');
await pool.executeNonQueryStatement(`
CREATE TABLE metrics (
device_id STRING TAG,
value DOUBLE FIELD
)
`);
// Switch to staging database
await pool.executeNonQueryStatement('USE staging');
await pool.executeNonQueryStatement(`
CREATE TABLE test_metrics (
device_id STRING TAG,
value DOUBLE FIELD
)
`);
// Query across databases using fully qualified names
const prodData = await pool.executeQueryStatement('SELECT * FROM production.metrics LIMIT 10');
const stagingData = await pool.executeQueryStatement('SELECT * FROM staging.test_metrics LIMIT 10');
await prodData.close();
await stagingData.close();
} finally {
await pool.close();
}
}
```
## 8. Best Practices
### 8.1 Table Design
**Use TAGs effectively:**
- Use TAGs for columns frequently used in WHERE clauses
- TAGs are indexed, enabling fast queries
- Keep TAG cardinality reasonable (avoid millions of unique values)
**Use ATTRIBUTEs for metadata:**
- Descriptive information that doesn't need indexing
- Device model, manufacturer, location, etc.
- Not used in WHERE clauses
**Use FIELDs for measurements:**
- Actual sensor readings and metrics
- Time-series data values
**Example:**
```typescript
// Good table design
CREATE TABLE sensor_data (
region_id STRING TAG, // Indexed, used in WHERE
device_id STRING TAG, // Indexed, used in WHERE
manufacturer STRING ATTRIBUTE, // Metadata, not indexed
model STRING ATTRIBUTE, // Metadata, not indexed
temperature FLOAT FIELD, // Measurement value
humidity FLOAT FIELD // Measurement value
)
// Poor design - using FIELD for identifiers
CREATE TABLE sensor_data (
temperature FLOAT FIELD,
humidity FLOAT FIELD,
device_id STRING FIELD // Should be TAG!
)
```
### 8.2 Query Optimization
**Filter by TAGs in WHERE clause:**
```typescript
// Good: Uses indexed TAGs
SELECT * FROM sensors
WHERE region_id = 'north' AND device_id = 'dev001'
// Poor: Filter by non-indexed FIELD
SELECT * FROM sensors
WHERE temperature > 25.0 // No TAG filtering
```
**Use appropriate LIMIT:**
```typescript
// Prevent loading too much data
SELECT * FROM sensors
WHERE region_id = 'north'
LIMIT 1000
```
**Use time range filters:**
```typescript
SELECT * FROM sensors
WHERE region_id = 'north'
AND timestamp >= ${Date.now() - 3600000}
AND timestamp <= ${Date.now()}
```
### 8.3 Connection Pool Management
**Size the pool appropriately:**
```typescript
const pool = new TableSessionPool({
nodeUrls: ['localhost:6667'],
maxPoolSize: 50, // Peak concurrent queries
minPoolSize: 10, // Keep warm connections
maxIdleTime: 60000, // Clean up after 1 minute idle
waitTimeout: 30000, // Wait max 30s for connection
});
```
**Monitor pool health:**
```typescript
setInterval(() => {
console.log('Pool Stats:');
console.log(` Total: ${pool.getPoolSize()}`);
console.log(` Available: ${pool.getAvailableSize()}`);
console.log(` In Use: ${pool.getInUseSize()}`);
}, 60000); // Every minute
```
### 8.4 Error Handling
```typescript
async function robustInsert(pool: TableSessionPool, data: any) {
try {
await pool.insertTablet(data);
console.log('Insert successful');
} catch (error) {
if (error.message.includes('Table does not exist')) {
console.log('Creating table...');
await createTable(pool);
await pool.insertTablet(data);
} else if (error.message.includes('Database does not exist')) {
console.log('Creating database...');
await createDatabase(pool);
await createTable(pool);
await pool.insertTablet(data);
} else {
console.error('Insert failed:', error);
throw error;
}
}
}
```
### 8.5 Resource Cleanup
```typescript
async function properCleanup() {
const pool = new TableSessionPool('localhost', 6667, {
username: 'root',
password: 'root',
});
await pool.open();
try {
const dataSet = await pool.executeQueryStatement('SELECT * FROM table1');
try {
while (await dataSet.hasNext()) {
// Process results
}
} finally {
await dataSet.close(); // Always close DataSet
}
} finally {
await pool.close(); // Always close pool
}
}
```
## 9. Troubleshooting
### 9.1 Common Issues
#### Database Does Not Exist
**Symptoms:**
```
Error: Database 'my_db' does not exist
```
**Solutions:**
```typescript
// Create database first
await pool.executeNonQueryStatement('CREATE DATABASE my_db');
await pool.executeNonQueryStatement('USE my_db');
// Or configure pool with existing database
const pool = new TableSessionPool('localhost', 6667, {
database: 'my_db', // Must exist
});
```
#### Table Does Not Exist
**Symptoms:**
```
Error: Table 'my_table' does not exist
```
**Solutions:**
```typescript
// Check if table exists
const dataSet = await pool.executeQueryStatement('SHOW TABLES');
// ... verify table exists
// Create table if needed
await pool.executeNonQueryStatement(`
CREATE TABLE my_table (...)
`);
```
#### Column Mismatch
**Symptoms:**
```
Error: Column count mismatch
```
**Solutions:**
- Ensure `columnNames`, `columnTypes`, and `columnCategories` have same length
- Verify `values` array matches column count
- Check table schema matches your data
```typescript
// Verify schema
const dataSet = await pool.executeQueryStatement('DESCRIBE my_table');
while (await dataSet.hasNext()) {
console.log(dataSet.next().getFields());
}
```
#### TTL Issues
**Symptoms:**
Data automatically deleted after some time
**Solutions:**
```typescript
// Check TTL setting
const dataSet = await pool.executeQueryStatement('SHOW TABLES');
// Look for TTL in table properties
// Modify TTL
await pool.executeNonQueryStatement(`
ALTER TABLE my_table SET PROPERTIES TTL=31536000000
`); // 1 year in milliseconds
```
### 9.2 Performance Issues
**Slow Queries:**
1. Add indexes by using TAGs appropriately
2. Use time range filters
3. Add LIMIT clauses
4. Consider table partitioning
**Slow Inserts:**
1. Increase batch size (100-1000 rows)
2. Use connection pooling
3. Consider multiple concurrent writers
4. Monitor server resources
### 9.3 Debugging
**Enable debug logging:**
```typescript
process.env.LOG_LEVEL = 'debug';
```
**Check SQL syntax:**
```typescript
try {
await pool.executeQueryStatement('EXPLAIN SELECT * FROM my_table');
} catch (error) {
console.error('Invalid SQL:', error.message);
}
```
**Monitor query execution:**
```typescript
const start = Date.now();
const dataSet = await pool.executeQueryStatement('SELECT ...');
console.log(`Query took ${Date.now() - start}ms`);
let rowCount = 0;
while (await dataSet.hasNext()) {
dataSet.next();
rowCount++;
}
console.log(`Returned ${rowCount} rows`);
```
### 9.4 Getting Help
- **Documentation**: [IoTDB Table Model Docs](https://iotdb.apache.org/)
- **GitHub Issues**: [Report bugs](https://github.com/CritasWang/@iotdb/client/issues)
- **Community**: dev@iotdb.apache.org
## Appendix A: Complete API Reference
### TableSessionPool Methods
- `open(enableRpcCompression?)` - Open connection pool
- `close()` - Close all sessions
- `executeQueryStatement(sql, timeout?)` - Execute SQL query
- `executeNonQueryStatement(sql)` - Execute DDL/DML
- `insertTablet(tablet)` - Batch insert into table
- `getPoolSize()` - Total sessions
- `getAvailableSize()` - Available sessions
- `getInUseSize()` - Active sessions
### SQL Statements
- `CREATE DATABASE database_name`
- `DROP DATABASE database_name`
- `USE database_name`
- `SHOW DATABASES`
- `SHOW TABLES`
- `CREATE TABLE table_name (...)`
- `DROP TABLE table_name`
- `ALTER TABLE table_name SET PROPERTIES TTL=<ms>`
- `SELECT ... FROM table_name WHERE ... LIMIT ...`
- `DESCRIBE table_name`
## Appendix B: Data Type Reference
See [data-types.md](data-types.md) for comprehensive data type documentation.
---
**Version**: 1.0.0
**Last Updated**: January 2024
**License**: Apache License 2.0