@@ -39,12 +39,13 @@ To install node-redis, simply:
39
39
npm install redis
40
40
```
41
41
42
- > "redis" is the "whole in one" package that includes all the other packages. If you only need a subset of the commands, you can install the individual packages. See the list below.
42
+ > "redis" is the "whole in one" package that includes all the other packages. If you only need a subset of the commands,
43
+ > you can install the individual packages. See the list below.
43
44
44
45
## Packages
45
46
46
47
| Name | Description |
47
- | ------------------------------------------------ | --------------------------------------------------------------------------------------------- |
48
+ | ---------------------------------------------- | ------------------------------------------------------------------------------------------- |
48
49
| [ ` redis ` ] ( ./packages/redis ) | The client with all the [ "redis-stack"] ( https://github.com/redis-stack/redis-stack ) modules |
49
50
| [ ` @redis/client ` ] ( ./packages/client ) | The base clients (i.e ` RedisClient ` , ` RedisCluster ` , etc.) |
50
51
| [ ` @redis/bloom ` ] ( ./packages/bloom ) | [ Redis Bloom] ( https://redis.io/docs/data-types/probabilistic/ ) commands |
@@ -53,7 +54,343 @@ npm install redis
53
54
| [ ` @redis/time-series ` ] ( ./packages/time-series ) | [ Redis Time-Series] ( https://redis.io/docs/data-types/timeseries/ ) commands |
54
55
| [ ` @redis/entraid ` ] ( ./packages/entraid ) | Secure token-based authentication for Redis clients using Microsoft Entra ID |
55
56
56
- > Looking for a high-level library to handle object mapping? See [ redis-om-node] ( https://github.com/redis/redis-om-node ) !
57
+ > Looking for a high-level library to handle object mapping?
58
+ > See [ redis-om-node] ( https://github.com/redis/redis-om-node ) !
59
+
60
+ ## Installation
61
+
62
+ Start a redis via docker:
63
+
64
+ ``` bash
65
+ docker run -p 6379:6379 -d redis:8.0-rc1
66
+ ```
67
+
68
+ To install node-redis, simply:
69
+
70
+ ``` bash
71
+ npm install redis
72
+ ```
73
+
74
+ Looking for a high-level library to handle object mapping? See [ redis-om-node] ( https://github.com/redis/redis-om-node ) !
75
+
76
+ ## Usage
77
+
78
+ ### Basic Example
79
+
80
+ ``` typescript
81
+ import { createClient } from " redis" ;
82
+
83
+ const client = await createClient ()
84
+ .on (" error" , (err ) => console .log (" Redis Client Error" , err ))
85
+ .connect ();
86
+
87
+ await client .set (" key" , " value" );
88
+ const value = await client .get (" key" );
89
+ client .destroy ();
90
+ ```
91
+
92
+ The above code connects to localhost on port 6379. To connect to a different host or port, use a connection string in
93
+ the format ` redis[s]://[[username][:password]@][host][:port][/db-number] ` :
94
+
95
+ ``` typescript
96
+ createClient ({
97
+ url:
" redis://alice:[email protected] :6380" ,
98
+ });
99
+ ```
100
+
101
+ You can also use discrete parameters, UNIX sockets, and even TLS to connect. Details can be found in
102
+ the [ client configuration guide] ( ./docs/client-configuration.md ) .
103
+
104
+ To check if the the client is connected and ready to send commands, use ` client.isReady ` which returns a boolean.
105
+ ` client.isOpen ` is also available. This returns ` true ` when the client's underlying socket is open, and ` false ` when it
106
+ isn't (for example when the client is still connecting or reconnecting after a network error).
107
+
108
+ ### Redis Commands
109
+
110
+ There is built-in support for all of the [ out-of-the-box Redis commands] ( https://redis.io/commands ) . They are exposed
111
+ using the raw Redis command names (` HSET ` , ` HGETALL ` , etc.) and a friendlier camel-cased version (` hSet ` , ` hGetAll ` ,
112
+ etc.):
113
+
114
+ ``` typescript
115
+ // raw Redis commands
116
+ await client .HSET (" key" , " field" , " value" );
117
+ await client .HGETALL (" key" );
118
+
119
+ // friendly JavaScript commands
120
+ await client .hSet (" key" , " field" , " value" );
121
+ await client .hGetAll (" key" );
122
+ ```
123
+
124
+ Modifiers to commands are specified using a JavaScript object:
125
+
126
+ ``` typescript
127
+ await client .set (" key" , " value" , {
128
+ EX: 10 ,
129
+ NX: true ,
130
+ });
131
+ ```
132
+
133
+ Replies will be transformed into useful data structures:
134
+
135
+ ``` typescript
136
+ await client .hGetAll (" key" ); // { field1: 'value1', field2: 'value2' }
137
+ await client .hVals (" key" ); // ['value1', 'value2']
138
+ ```
139
+
140
+ ` Buffer ` s are supported as well:
141
+
142
+ ``` typescript
143
+ await client .hSet (" key" , " field" , Buffer .from (" value" )); // 'OK'
144
+ await client .hGetAll (commandOptions ({ returnBuffers: true }), " key" ); // { field: <Buffer 76 61 6c 75 65> }
145
+ ```
146
+
147
+ ### Unsupported Redis Commands
148
+
149
+ If you want to run commands and/or use arguments that Node Redis doesn't know about (yet!) use ` .sendCommand() ` :
150
+
151
+ ``` typescript
152
+ await client .sendCommand ([" SET" , " key" , " value" , " NX" ]); // 'OK'
153
+
154
+ await client .sendCommand ([" HGETALL" , " key" ]); // ['key1', 'field1', 'key2', 'field2']
155
+ ```
156
+
157
+ ### Transactions (Multi/Exec)
158
+
159
+ Start a [ transaction] ( https://redis.io/topics/transactions ) by calling ` .multi() ` , then chaining your commands. When
160
+ you're done, call ` .exec() ` and you'll get an array back with your results:
161
+
162
+ ``` typescript
163
+ await client .set (" another-key" , " another-value" );
164
+
165
+ const [setKeyReply, otherKeyValue] = await client
166
+ .multi ()
167
+ .set (" key" , " value" )
168
+ .get (" another-key" )
169
+ .exec (); // ['OK', 'another-value']
170
+ ```
171
+
172
+ You can also [ watch] ( https://redis.io/topics/transactions#optimistic-locking-using-check-and-set ) keys by calling
173
+ ` .watch() ` . Your transaction will abort if any of the watched keys change.
174
+
175
+ To dig deeper into transactions, check out the [ Isolated Execution Guide] ( ./docs/isolated-execution.md ) .
176
+
177
+ ### Blocking Commands
178
+
179
+ In v4, ` RedisClient ` had the ability to create a pool of connections using an "Isolation Pool" on top of the "main"
180
+ connection. However, there was no way to use the pool without a "main" connection:
181
+
182
+ ``` javascript
183
+ const client = await createClient ()
184
+ .on (" error" , (err ) => console .error (err))
185
+ .connect ();
186
+
187
+ await client .ping (client .commandOptions ({ isolated: true }));
188
+ ```
189
+
190
+ In v5 we've extracted this pool logic into its own class—` RedisClientPool ` :
191
+
192
+ ``` javascript
193
+ const pool = await createClientPool ()
194
+ .on (" error" , (err ) => console .error (err))
195
+ .connect ();
196
+
197
+ await pool .ping ();
198
+ ```
199
+
200
+ To learn more about isolated execution, check out the [ guide] ( ./docs/isolated-execution.md ) .
201
+
202
+ ### Pub/Sub
203
+
204
+ See the [ Pub/Sub overview] ( ./docs/pub-sub.md ) .
205
+
206
+ ### Scan Iterator
207
+
208
+ [ ` SCAN ` ] ( https://redis.io/commands/scan ) results can be looped over
209
+ using [ async iterators] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator ) :
210
+
211
+ ``` typescript
212
+ for await (const key of client .scanIterator ()) {
213
+ // use the key!
214
+ await client .get (key );
215
+ }
216
+ ```
217
+
218
+ This works with ` HSCAN ` , ` SSCAN ` , and ` ZSCAN ` too:
219
+
220
+ ``` typescript
221
+ for await (const { field, value } of client .hScanIterator (" hash" )) {
222
+ }
223
+ for await (const member of client .sScanIterator (" set" )) {
224
+ }
225
+ for await (const { score, value } of client .zScanIterator (" sorted-set" )) {
226
+ }
227
+ ```
228
+
229
+ You can override the default options by providing a configuration object:
230
+
231
+ ``` typescript
232
+ client .scanIterator ({
233
+ TYPE: " string" , // `SCAN` only
234
+ MATCH: " patter*" ,
235
+ COUNT: 100 ,
236
+ });
237
+ ```
238
+
239
+ ### [ Programmability] ( https://redis.io/docs/manual/programmability/ )
240
+
241
+ Redis provides a programming interface allowing code execution on the redis server.
242
+
243
+ #### [ Functions] ( https://redis.io/docs/manual/programmability/functions-intro/ )
244
+
245
+ The following example retrieves a key in redis, returning the value of the key, incremented by an integer. For example,
246
+ if your key _ foo_ has the value _ 17_ and we run ` add('foo', 25) ` , it returns the answer to Life, the Universe and
247
+ Everything.
248
+
249
+ ``` lua
250
+ # !lua name = library
251
+
252
+ redis .register_function {
253
+ function_name = ' add' ,
254
+ callback = function (keys , args ) return redis .call (' GET' , keys [1 ]) + args [1 ] end ,
255
+ flags = { ' no-writes' }
256
+ }
257
+ ```
258
+
259
+ Here is the same example, but in a format that can be pasted into the ` redis-cli ` .
260
+
261
+ ```
262
+ FUNCTION LOAD "#!lua name=library\nredis.register_function{function_name=\"add\", callback=function(keys, args) return redis.call('GET', keys[1])+args[1] end, flags={\"no-writes\"}}"
263
+ ```
264
+
265
+ Load the prior redis function on the _ redis server_ before running the example below.
266
+
267
+ ``` typescript
268
+ import { createClient } from " redis" ;
269
+
270
+ const client = createClient ({
271
+ functions: {
272
+ library: {
273
+ add: {
274
+ NUMBER_OF_KEYS: 1 ,
275
+ transformArguments(key : string , toAdd : number ): Array <string > {
276
+ return [key , toAdd .toString ()];
277
+ },
278
+ transformReply(reply : number ): number {
279
+ return reply ;
280
+ },
281
+ },
282
+ },
283
+ },
284
+ });
285
+
286
+ await client .connect ();
287
+
288
+ await client .set (" key" , " 1" );
289
+ await client .library .add (" key" , 2 ); // 3
290
+ ```
291
+
292
+ #### [ Lua Scripts] ( https://redis.io/docs/manual/programmability/eval-intro/ )
293
+
294
+ The following is an end-to-end example of the prior concept.
295
+
296
+ ``` typescript
297
+ import { createClient , defineScript } from " redis" ;
298
+
299
+ const client = createClient ({
300
+ scripts: {
301
+ add: defineScript ({
302
+ NUMBER_OF_KEYS: 1 ,
303
+ SCRIPT: ' return redis.call("GET", KEYS[1]) + ARGV[1];' ,
304
+ transformArguments(key : string , toAdd : number ): Array <string > {
305
+ return [key , toAdd .toString ()];
306
+ },
307
+ transformReply(reply : number ): number {
308
+ return reply ;
309
+ },
310
+ }),
311
+ },
312
+ });
313
+
314
+ await client .connect ();
315
+
316
+ await client .set (" key" , " 1" );
317
+ await client .add (" key" , 2 ); // 3
318
+ ```
319
+
320
+ ### Disconnecting
321
+
322
+ The ` QUIT ` command has been deprecated in Redis 7.2 and should now also be considered deprecated in Node-Redis. Instead
323
+ of sending a ` QUIT ` command to the server, the client can simply close the network connection.
324
+
325
+ ` client.QUIT/quit() ` is replaced by ` client.close() ` . and, to avoid confusion, ` client.disconnect() ` has been renamed to
326
+ ` client.destroy() ` .
327
+
328
+ ``` typescript
329
+ await client .destroy ();
330
+ ```
331
+
332
+ ### Auto-Pipelining
333
+
334
+ Node Redis will automatically pipeline requests that are made during the same "tick".
335
+
336
+ ``` typescript
337
+ client .set (" Tm9kZSBSZWRpcw==" , " users:1" );
338
+ client .sAdd (" users:1:tokens" , " Tm9kZSBSZWRpcw==" );
339
+ ```
340
+
341
+ Of course, if you don't do something with your Promises you're certain to
342
+ get [ unhandled Promise exceptions] ( https://nodejs.org/api/process.html#process_event_unhandledrejection ) . To take
343
+ advantage of auto-pipelining and handle your Promises, use ` Promise.all() ` .
344
+
345
+ ``` typescript
346
+ await Promise .all ([
347
+ client .set (" Tm9kZSBSZWRpcw==" , " users:1" ),
348
+ client .sAdd (" users:1:tokens" , " Tm9kZSBSZWRpcw==" ),
349
+ ]);
350
+ ```
351
+
352
+ ### Clustering
353
+
354
+ Check out the [ Clustering Guide] ( ./docs/clustering.md ) when using Node Redis to connect to a Redis Cluster.
355
+
356
+ ### Events
357
+
358
+ The Node Redis client class is an Nodejs EventEmitter and it emits an event each time the network status changes:
359
+
360
+ | Name | When | Listener arguments |
361
+ | ----------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------- |
362
+ | ` connect ` | Initiating a connection to the server | _ No arguments_ |
363
+ | ` ready ` | Client is ready to use | _ No arguments_ |
364
+ | ` end ` | Connection has been closed (via ` .disconnect() ` ) | _ No arguments_ |
365
+ | ` error ` | An error has occurred—usually a network issue such as "Socket closed unexpectedly" | ` (error: Error) ` |
366
+ | ` reconnecting ` | Client is trying to reconnect to the server | _ No arguments_ |
367
+ | ` sharded-channel-moved ` | See [ here] ( ./docs/pub-sub.md#sharded-channel-moved-event ) | See [ here] ( ./docs/pub-sub.md#sharded-channel-moved-event ) |
368
+
369
+ > :warning : You ** MUST** listen to ` error ` events. If a client doesn't have at least one ` error ` listener registered and
370
+ > an ` error ` occurs, that error will be thrown and the Node.js process will exit. See the [ > ` EventEmitter ` docs] ( https://nodejs.org/api/events.html#events_error_events ) for more details.
371
+
372
+ > The client will not emit [ any other events] ( ./docs/v3-to-v4.md#all-the-removed-events ) beyond those listed above.
373
+
374
+ ## Supported Redis versions
375
+
376
+ Node Redis is supported with the following versions of Redis:
377
+
378
+ | Version | Supported |
379
+ | ------- | ------------------ |
380
+ | 8.0.z | :heavy_check_mark : |
381
+ | 7.0.z | :heavy_check_mark : |
382
+ | 6.2.z | :heavy_check_mark : |
383
+ | 6.0.z | :heavy_check_mark : |
384
+ | 5.0.z | :heavy_check_mark : |
385
+ | < 5.0 | :x : |
386
+
387
+ > Node Redis should work with older versions of Redis, but it is not fully tested and we cannot offer support.
388
+
389
+ ## Migration
390
+
391
+ - [ From V3 to V4] ( docs/v3-to-v4.md )
392
+ - [ From V4 to V5] ( docs/v4-to-v5.md )
393
+ - [ V5] ( docs/v5.md )
57
394
58
395
## Contributing
59
396
0 commit comments