212 lines
5.4 KiB
Markdown
212 lines
5.4 KiB
Markdown
|
---
|
||
|
title: Redis
|
||
|
pagination_prev: demos/grid
|
||
|
pagination_next: demos/worker
|
||
|
sidebar_custom_props:
|
||
|
type: nosql
|
||
|
---
|
||
|
|
||
|
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.
|
||
|
|
||
|
![SheetJSRedis.xlsx](pathname:///nosql/sheetjsredis.png)
|
||
|
|
||
|
## 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:
|
||
|
|
||
|
```bash
|
||
|
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz redis@4.6.4
|
||
|
node SheetJSRedisTest.mjs
|
||
|
```
|
||
|
|
||
|
Inspect the output and compare with the data in `SheetJSRedisTest.mjs`.
|
||
|
|
||
|
Open `SheetJSRedis.xlsx` and verify the columns have the correct data
|