1- ## QuestDB Node.js Client
1+ # QuestDB Node.js Client
2+
3+ ## Requirements
4+
5+ The client requires Node.js v16 or newer version.
26
37## Installation
48``` shell
5- npm install @questdb/nodejs-client
9+ npm i -s @questdb/nodejs-client
610```
711
812## Examples
913
1014### Basic API usage
15+
1116``` javascript
12- const { Sender } = require (" @questdb/nodejs-client" );
17+ const { Sender } = require (' @questdb/nodejs-client' );
1318
1419async function run () {
15- // create a sender with a 4k buffer
16- // it is important to size the buffer correctly so messages can fit
17- const sender = new Sender ({bufferSize: 4096 });
20+ const sender = new Sender ();
1821
1922 // connect to QuestDB
2023 // host and port are required in connect options
21- await sender .connect ({port: 9009 , host: " localhost" });
24+ await sender .connect ({port: 9009 , host: ' localhost' });
2225
2326 // add rows to the buffer of the sender
24- sender .table (" prices" ).symbol (" instrument" , " EURUSD" )
25- .floatColumn (" bid" , 1.0195 ).floatColumn (" ask" , 1.0221 ).atNow ();
26- sender .table (" prices" ).symbol (" instrument" , " GBPUSD" )
27- .floatColumn (" bid" , 1.2076 ).floatColumn (" ask" , 1.2082 ).atNow ();
27+ sender .table (' prices' ).symbol (' instrument' , ' EURUSD' )
28+ .floatColumn (' bid' , 1.0195 ).floatColumn (' ask' , 1.0221 )
29+ .at (Date .now (), ' ms' );
30+ sender .table (' prices' ).symbol (' instrument' , ' GBPUSD' )
31+ .floatColumn (' bid' , 1.2076 ).floatColumn (' ask' , 1.2082 )
32+ .at (Date .now (), ' ms' );
2833
2934 // flush the buffer of the sender, sending the data to QuestDB
3035 // the buffer is cleared after the data is sent and the sender is ready to accept new data
3136 await sender .flush ();
3237
3338 // add rows to the buffer again and send it to the server
34- sender .table (" prices" ).symbol (" instrument" , " EURUSD" )
35- .floatColumn (" bid" , 1.0197 ).floatColumn (" ask" , 1.0224 ).atNow ();
39+ sender .table (' prices' ).symbol (' instrument' , ' EURUSD' )
40+ .floatColumn (' bid' , 1.0197 ).floatColumn (' ask' , 1.0224 )
41+ .at (Date .now (), ' ms' );
3642 await sender .flush ();
3743
3844 // close the connection after all rows ingested
3945 await sender .close ();
4046 return new Promise (resolve => resolve (0 ));
4147}
4248
43- run ().then (value => console .log (value)).catch (err => console .log (err));
49+ run ()
50+ .then (console .log )
51+ .catch (console .error );
4452```
4553
4654### Authentication and secure connection
55+
4756``` javascript
48- const { Sender } = require (" @questdb/nodejs-client" );
57+ const { Sender } = require (' @questdb/nodejs-client' );
4958
5059async function run () {
5160 // construct a JsonWebKey
52- const CLIENT_ID = " testapp" ;
53- const PRIVATE_KEY = " 9b9x5WhJywDEuo1KGQWSPNxtX-6X6R2BRCKhYMMY6n8" ;
61+ const CLIENT_ID = ' testapp' ;
62+ const PRIVATE_KEY = ' 9b9x5WhJywDEuo1KGQWSPNxtX-6X6R2BRCKhYMMY6n8' ;
5463 const PUBLIC_KEY = {
55- x: " aultdA0PjhD_cWViqKKyL5chm6H1n-BiZBo_48T-uqc" ,
56- y: " __ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg"
64+ x: ' aultdA0PjhD_cWViqKKyL5chm6H1n-BiZBo_48T-uqc' ,
65+ y: ' __ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg'
5766 };
5867 const JWK = {
5968 ... PUBLIC_KEY,
6069 d: PRIVATE_KEY ,
6170 kid: CLIENT_ID ,
62- kty: " EC " ,
63- crv: " P-256" ,
71+ kty: ' EC ' ,
72+ crv: ' P-256' ,
6473 };
6574
6675 // pass the JsonWebKey to the sender
6776 // will use it for authentication
68- const sender = new Sender ({bufferSize : 4096 , jwk: JWK });
77+ const sender = new Sender ({jwk: JWK });
6978
7079 // connect() takes an optional second argument
7180 // if 'true' passed the connection is secured with TLS encryption
72- await sender .connect ({port: 9009 , host: " localhost" }, true );
81+ await sender .connect ({port: 9009 , host: ' localhost' }, true );
7382
7483 // send the data over the authenticated and secure connection
75- sender .table (" prices" ).symbol (" instrument" , " EURUSD" )
76- .floatColumn (" bid" , 1.0197 ).floatColumn (" ask" , 1.0224 ).atNow ();
84+ sender .table (' prices' ).symbol (' instrument' , ' EURUSD' )
85+ .floatColumn (' bid' , 1.0197 ).floatColumn (' ask' , 1.0224 )
86+ .at (Date .now (), ' ms' );
7787 await sender .flush ();
7888
7989 // close the connection after all rows ingested
8090 await sender .close ();
81- return new Promise (resolve => resolve (0 ));
8291}
8392
84- run ().then ( value => console . log (value)). catch (err => console .log (err) );
93+ run ().catch (console .error );
8594```
8695
8796### TypeScript example
97+
8898``` typescript
89- import { Sender } from " @questdb/nodejs-client" ;
99+ import { Sender } from ' @questdb/nodejs-client' ;
90100
91101async function run(): Promise <number > {
92102 // construct a JsonWebKey
93- const CLIENT_ID: string = " testapp" ;
94- const PRIVATE_KEY: string = " 9b9x5WhJywDEuo1KGQWSPNxtX-6X6R2BRCKhYMMY6n8" ;
103+ const CLIENT_ID: string = ' testapp' ;
104+ const PRIVATE_KEY: string = ' 9b9x5WhJywDEuo1KGQWSPNxtX-6X6R2BRCKhYMMY6n8' ;
95105 const PUBLIC_KEY: { x: string , y: string } = {
96- x: " aultdA0PjhD_cWViqKKyL5chm6H1n-BiZBo_48T-uqc" ,
97- y: " __ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg"
106+ x: ' aultdA0PjhD_cWViqKKyL5chm6H1n-BiZBo_48T-uqc' ,
107+ y: ' __ptaol41JWSpTTL525yVEfzmY8A6Vi_QrW1FjKcHMg'
98108 };
99109 const JWK: { x: string , y: string , kid: string , kty: string , d: string , crv: string } = {
100110 ... PUBLIC_KEY ,
101111 d: PRIVATE_KEY ,
102112 kid: CLIENT_ID ,
103- kty: " EC " ,
104- crv: " P-256" ,
113+ kty: ' EC ' ,
114+ crv: ' P-256' ,
105115 };
106116
107117 // pass the JsonWebKey to the sender
108118 // will use it for authentication
109- const sender: Sender = new Sender ({bufferSize: 4096 , jwk: JWK });
119+ const sender: Sender = new Sender ({jwk: JWK });
110120
111121 // connect() takes an optional second argument
112122 // if 'true' passed the connection is secured with TLS encryption
113- await sender .connect ({port: 9009 , host: " localhost" }, true );
123+ await sender .connect ({port: 9009 , host: ' localhost' }, true );
114124
115125 // send the data over the authenticated and secure connection
116- sender .table (" prices" ).symbol (" instrument" , " EURUSD" )
117- .floatColumn (" bid" , 1.0197 ).floatColumn (" ask" , 1.0224 ).atNow ( );
126+ sender .table (' prices' ).symbol (' instrument' , ' EURUSD' )
127+ .floatColumn (' bid' , 1.0197 ).floatColumn (' ask' , 1.0224 ).at ( Date . now (), ' ms ' );
118128 await sender .flush ();
119129
120130 // close the connection after all rows ingested
121131 await sender .close ();
122- return new Promise (resolve => resolve (0 ));
123132}
124133
125- run ().then ( value => console . log ( value )). catch (err => console .log ( err ) );
134+ run ().catch (console .error );
126135```
127136
128137### Worker threads example
138+
129139``` javascript
130- const { Sender } = require (" @questdb/nodejs-client" );
140+ const { Sender } = require (' @questdb/nodejs-client' );
131141const { Worker , isMainThread , parentPort , workerData } = require (' worker_threads' );
132142
133143// fake venue
@@ -136,7 +146,7 @@ function* venue(ticker) {
136146 let end = false ;
137147 setTimeout (() => { end = true ; }, rndInt (5000 ));
138148 while (! end) {
139- yield {" ticker" : ticker, " price" : Math .random ()};
149+ yield {' ticker' : ticker, ' price' : Math .random ()};
140150 }
141151}
142152
@@ -153,35 +163,37 @@ async function subscribe(ticker, onTick) {
153163
154164async function run () {
155165 if (isMainThread) {
156- const tickers = [" t1 " , " t2 " , " t3 " , " t4 " ];
166+ const tickers = [' t1 ' , ' t2 ' , ' t3 ' , ' t4 ' ];
157167 // main thread to start a worker thread for each ticker
158168 for (let ticker in tickers) {
159169 const worker = new Worker (__filename , { workerData: { ticker: ticker } })
160170 .on (' error' , (err ) => { throw err; })
161171 .on (' exit' , () => { console .log (` ${ ticker} thread exiting...` ); })
162- .on (' message' , (msg ) => { console .log (" Ingested " + msg .count + " prices for ticker " + msg .ticker ); });
172+ .on (' message' , (msg ) => {
173+ console .log (` Ingested ${ msg .count } prices for ticker ${ msg .ticker } ` );
174+ });
163175 }
164176 } else {
165177 // it is important that each worker has a dedicated sender object
166178 // threads cannot share the sender because they would write into the same buffer
167- const sender = new Sender ({ bufferSize : 4096 } );
168- await sender .connect ({ port: 9009 , host: " localhost" });
179+ const sender = new Sender ();
180+ await sender .connect ({ port: 9009 , host: ' localhost' });
169181
170182 // subscribe for the market data of the ticker assigned to the worker
171183 // ingest each price update into the database using the sender
172184 let count = 0 ;
173185 await subscribe (workerData .ticker , async (tick ) => {
174186 sender
175- .table (" prices" )
176- .symbol (" ticker" , tick .ticker )
177- .floatColumn (" price" , tick .price )
178- .atNow ( );
187+ .table (' prices' )
188+ .symbol (' ticker' , tick .ticker )
189+ .floatColumn (' price' , tick .price )
190+ .at ( Date . now (), ' ms ' );
179191 await sender .flush ();
180192 count++ ;
181193 });
182194
183195 // let the main thread know how many prices were ingested
184- parentPort .postMessage ({" ticker" : workerData .ticker , " count" : count});
196+ parentPort .postMessage ({' ticker' : workerData .ticker , ' count' : count});
185197
186198 // close the connection to the database
187199 await sender .close ();
@@ -196,5 +208,7 @@ function rndInt(limit) {
196208 return Math .floor ((Math .random () * limit) + 1 );
197209}
198210
199- run ().catch ((err ) => console .log (err));
211+ run ()
212+ .then (console .log )
213+ .catch (console .error );
200214```
0 commit comments