| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: Redis | 
					
						
							| 
									
										
										
										
											2023-02-28 11:40:44 +00:00
										 |  |  | pagination_prev: demos/desktop/index | 
					
						
							|  |  |  | pagination_next: demos/local/index | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | sidebar_custom_props: | 
					
						
							|  |  |  |   type: nosql | 
					
						
							|  |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | import current from '/version.js'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | Redis has 5 core data types: "String", List", "Set", "Sorted Set", and "Hash". | 
					
						
							|  |  |  | Since the keys and values are limited to simple strings (and numbers), it is | 
					
						
							|  |  |  | possible to store complete databases in a single worksheet. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Integration Details
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [`SheetJSRedis.mjs`](pathname:///nosql/SheetJSRedis.mjs) exports the methods: | 
					
						
							|  |  |  | - `redis_to_ws` creates a SheetJS worksheet by querying a redis client | 
					
						
							|  |  |  | - `ws_to_redis` creates an array of query objects from the SheetJS worksheet | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The first row holds the data type and the second row holds the property name. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The "Exporting Data" snippets generate arrays of arrays that can be added to a | 
					
						
							|  |  |  | worksheet using `sheet_add_aoa`.  Since the data is column-oriented, the goal is | 
					
						
							|  |  |  | to add the data starting in the first row of the column after the data: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function add_aoa_to_next_column(worksheet, aoa) { | 
					
						
							|  |  |  |   /* get range of worksheet */ | 
					
						
							|  |  |  |   const range = XLSX.utils.decode_range(worksheet["!ref"]) | 
					
						
							|  |  |  |   /* the origin to write new data will start in the column after the range */ | 
					
						
							|  |  |  |   const origin = XLSX.utils.encode_cell({ | 
					
						
							|  |  |  |     r: 0, // start on first row | 
					
						
							|  |  |  |     c: range.e.c + 1 // column after end | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   /* add data */ | 
					
						
							|  |  |  |   XLSX.utils.sheet_add_aoa(worksheet, aoa, { origin }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The "Importing Data" snippets generate redis queries. The `ws_to_redis` function | 
					
						
							|  |  |  | first generates an array of arrays with `sheet_to_json`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const aoa = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Strings
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Strings can be stored in a unified String table. The first column holds keys | 
					
						
							|  |  |  | and the second column holds values: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | XXX|    A    |   B   | | 
					
						
							|  |  |  | ---+---------+-------+ | 
					
						
							|  |  |  |  1 | Strings |       | | 
					
						
							|  |  |  |  2 |         |       | | 
					
						
							|  |  |  |  3 | Hello   | World | | 
					
						
							|  |  |  |  4 | Sheet   | JS    | | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS array-of-arrays representation of the string table is an array of | 
					
						
							|  |  |  | key/value pairs: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const aoa = ["Strings"]; aoa.length = 2; // [ "Strings", empty ] | 
					
						
							|  |  |  | const keys = await client.KEYS("*"); | 
					
						
							|  |  |  | for(let key of keys) { | 
					
						
							|  |  |  |   const type = await client.TYPE(key); | 
					
						
							|  |  |  |   // highlight-start | 
					
						
							|  |  |  |   if(type == "string") aoa.push([key, await client.GET(key)]); | 
					
						
							|  |  |  |   // highlight-end | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Lists
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Lists are unidimensional and can be stored in their own columns. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | XXX|    C    | | 
					
						
							|  |  |  | ---+---------+ | 
					
						
							|  |  |  |  1 | List    | | 
					
						
							|  |  |  |  2 | List1   | | 
					
						
							|  |  |  |  3 | List1V1 | | 
					
						
							|  |  |  |  4 | List1V2 | | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS array-of-arrays representation of lists is a column of values. | 
					
						
							|  |  |  | `LRANGE` returns a simple array of values. `sheet_add_aoa` interprets the result | 
					
						
							|  |  |  | as one row. The code transposes the result with `values.map(v => [v])`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const values = await client.LRANGE(key, 0, -1); | 
					
						
							|  |  |  | const aoa = [ ["List"], [key] ].concat(values.map(v => [v])); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Sets
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Sets are unidimensional and can be stored in their own columns. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | XXX|   D   | | 
					
						
							|  |  |  | ---+-------+ | 
					
						
							|  |  |  |  1 | Set   | | 
					
						
							|  |  |  |  2 | Set1  | | 
					
						
							|  |  |  |  3 | Set1A | | 
					
						
							|  |  |  |  4 | Set1B | | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS array-of-arrays representation of sets is a column of values. | 
					
						
							|  |  |  | `SMEMBERS` returns a simple array of values. `sheet_add_aoa` interprets result | 
					
						
							|  |  |  | as one row. The code transposes the result with `values.map(v => [v])`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const values = await client.SMEMBERS(key); | 
					
						
							|  |  |  | const aoa = [ ["Set"], [key] ].concat(values.map(v => [v])); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Sorted Sets
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Sorted Sets have an associated score which can be stored in the second column. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | XXX|    E    | F | | 
					
						
							|  |  |  | ---+---------+---+ | 
					
						
							|  |  |  |  1 | Sorted  |   | | 
					
						
							|  |  |  |  2 | ZSet1   |   | | 
					
						
							|  |  |  |  3 | Key1    | 1 | | 
					
						
							|  |  |  |  4 | Key2    | 2 | | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS array-of-arrays representation is an array of key/score pairs. | 
					
						
							|  |  |  | `ZRANGE_WITHSCORES` returns an array of objects which can be reshaped. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const values = await client.ZRANGE_WITHSCORES(key, 0, -1); | 
					
						
							|  |  |  | const aoa = [ ["Sorted"], [key] ].concat(values.map(v => [v.value, v.score])); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Hashes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Hashes are stored like the string table, with key and value columns in order. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | XXX|   G   |   H   | | 
					
						
							|  |  |  | ---+-------+-------+ | 
					
						
							|  |  |  |  1 | Hash  |       | | 
					
						
							|  |  |  |  2 | Hash1 |       | | 
					
						
							|  |  |  |  3 | Key1  | Val1  | | 
					
						
							|  |  |  |  4 | Key2  | Val2  | | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The SheetJS array-of-arrays representation is an array of key/value pairs. | 
					
						
							|  |  |  | `HGETALL` returns a plain object which can be converted using `Object.entries`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const values = await client.HGETALL(key); | 
					
						
							|  |  |  | const aoa = [ ["Hash"], [key] ].concat(Object.entries(values)); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Complete Example
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This demo was last tested on 2023 February 23 with Redis 7.0.8, Redis connector | 
					
						
							|  |  |  | module 4.6.4 and NodeJS 18.14.2. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::warning | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The most recent version of the `redis` node module does not work with most | 
					
						
							|  |  |  | versions of NodeJS. It is "ESM-only", requiring NodeJS 18 or later. As a result, | 
					
						
							|  |  |  | this demo also requires NodeJS version 18. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Questions regarding the `redis` library and the decision to drop traditional | 
					
						
							|  |  |  | NodeJS "CommonJS" module support should be directed to the Redis team. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 0) Set up and start a local Redis server.  On Intel macOS: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | brew install redis@7.0.8 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) Download the following scripts: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - [`SheetJSRedis.mjs`](pathname:///nosql/SheetJSRedis.mjs) | 
					
						
							|  |  |  | - [`SheetJSRedisTest.mjs`](pathname:///nosql/SheetJSRedisTest.mjs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | curl -LO https://docs.sheetjs.com/nosql/SheetJSRedis.mjs | 
					
						
							|  |  |  | curl -LO https://docs.sheetjs.com/nosql/SheetJSRedisTest.mjs | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) Install dependencies and run: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 09:12:19 +00:00
										 |  |  | <pre><code parentName="pre" {...{"className": "language-bash"}}>{`\ | 
					
						
							|  |  |  | npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz redis@4.6.4 | 
					
						
							|  |  |  | node SheetJSRedisTest.mjs`} | 
					
						
							|  |  |  | </code></pre> | 
					
						
							| 
									
										
										
										
											2023-02-24 07:46:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Inspect the output and compare with the data in `SheetJSRedisTest.mjs`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Open `SheetJSRedis.xlsx` and verify the columns have the correct data |