You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-04 15:02:09 +03:00
Updates examples. (#2219)
* Updates examples. * Added command link for hset.
This commit is contained in:
@@ -53,7 +53,7 @@ When adding a new example, please follow these guidelines:
|
|||||||
* Use semicolons
|
* Use semicolons
|
||||||
* Use `async` and `await`
|
* Use `async` and `await`
|
||||||
* Use single quotes, `'hello'` not `"hello"`
|
* Use single quotes, `'hello'` not `"hello"`
|
||||||
* Place your example code in a single `async` function where possible, named according to the file name e.g. `add-to-stream.js` would contain `const addtoStream = async () => { ... };`, and call this function at the end of the file e.g. `addToStream();`
|
* Use [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) when embedding expressions in strings
|
||||||
* Unless your example requires a connection string, assume Redis is on the default localhost port 6379 with no password
|
* Unless your example requires a connection string, assume Redis is on the default localhost port 6379 with no password
|
||||||
* Use meaningful example data, let's not use `foo`, `bar`, `baz` etc!
|
* Use meaningful example data, let's not use `foo`, `bar`, `baz` etc!
|
||||||
* Leave an empty line at the end of your `.js` file
|
* Leave an empty line at the end of your `.js` file
|
||||||
@@ -71,18 +71,17 @@ Here's a starter template for adding a new example, imagine this is stored in `d
|
|||||||
|
|
||||||
// Set up the data in redis-cli using these commands:
|
// Set up the data in redis-cli using these commands:
|
||||||
// <add your command(s) here, one per line>
|
// <add your command(s) here, one per line>
|
||||||
|
//
|
||||||
|
// Alternatively, add code that sets up the data.
|
||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function doSomething() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Add your example code here...
|
// Add your example code here...
|
||||||
|
|
||||||
await client.quit();
|
await client.quit();
|
||||||
}
|
|
||||||
|
|
||||||
doSomething();
|
|
||||||
```
|
```
|
||||||
|
@@ -6,27 +6,25 @@
|
|||||||
|
|
||||||
import { createClient, commandOptions } from 'redis';
|
import { createClient, commandOptions } from 'redis';
|
||||||
|
|
||||||
async function blockingListPop() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
const keyName = 'keyName';
|
const keyName = 'keyName';
|
||||||
|
|
||||||
const blpopPromise = client.blPop(
|
const blpopPromise = client.blPop(
|
||||||
commandOptions({ isolated: true }),
|
commandOptions({ isolated: true }),
|
||||||
keyName,
|
keyName,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
await client.lPush(keyName, 'value');
|
await client.lPush(keyName, 'value');
|
||||||
|
|
||||||
await blpopPromise;
|
const listItem = await blpopPromise;
|
||||||
|
|
||||||
console.log('blpopPromise resolved');
|
console.log('blpopPromise resolved');
|
||||||
console.log(keyName);
|
// listItem will be:
|
||||||
|
// {"key":"keyName","element":"value"}
|
||||||
|
console.log(`listItem is '${JSON.stringify(listItem)}'`);
|
||||||
|
|
||||||
await client.quit();
|
await client.quit();
|
||||||
}
|
|
||||||
|
|
||||||
blockingListPop();
|
|
||||||
|
@@ -1,79 +1,80 @@
|
|||||||
// This example demonstrates the use of the Bloom Filter
|
// This example demonstrates the use of the Bloom Filter
|
||||||
// in the RedisBloom module (https://redisbloom.io/)
|
// in the RedisBloom module (https://redis.io/docs/stack/bloom/)
|
||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function bloomFilter() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Delete any pre-existing Bloom Filter.
|
// Delete any pre-existing Bloom Filter.
|
||||||
await client.del('mybloom');
|
await client.del('mybloom');
|
||||||
|
|
||||||
// Reserve a Bloom Filter with configurable error rate and capacity.
|
// Reserve a Bloom Filter with configurable error rate and capacity.
|
||||||
// https://oss.redis.com/redisbloom/Bloom_Commands/#bfreserve
|
// https://redis.io/commands/bf.reserve/
|
||||||
try {
|
try {
|
||||||
await client.bf.reserve('mybloom', 0.01, 1000);
|
await client.bf.reserve('mybloom', 0.01, 1000);
|
||||||
console.log('Reserved Bloom Filter.');
|
console.log('Reserved Bloom Filter.');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message.endsWith('item exists')) {
|
if (e.message.endsWith('item exists')) {
|
||||||
console.log('Bloom Filter already reserved.');
|
console.log('Bloom Filter already reserved.');
|
||||||
} else {
|
} else {
|
||||||
console.log('Error, maybe RedisBloom is not installed?:');
|
console.log('Error, maybe RedisBloom is not installed?:');
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add items to Bloom Filter individually with BF.ADD command.
|
|
||||||
await Promise.all([
|
|
||||||
client.bf.add('mybloom', 'leibale'),
|
|
||||||
client.bf.add('mybloom', 'simon'),
|
|
||||||
client.bf.add('mybloom', 'guy'),
|
|
||||||
client.bf.add('mybloom', 'suze'),
|
|
||||||
client.bf.add('mybloom', 'brian'),
|
|
||||||
client.bf.add('mybloom', 'steve'),
|
|
||||||
client.bf.add('mybloom', 'kyle'),
|
|
||||||
client.bf.add('mybloom', 'josefin'),
|
|
||||||
client.bf.add('mybloom', 'alex'),
|
|
||||||
client.bf.add('mybloom', 'nava'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Add multiple items to Bloom Filter at once with BF.MADD command.
|
|
||||||
await client.bf.mAdd('mybloom', [
|
|
||||||
'kaitlyn',
|
|
||||||
'rachel'
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log('Added members to Bloom Filter.');
|
|
||||||
|
|
||||||
// Check whether a member exists with the BF.EXISTS command.
|
|
||||||
const simonExists = await client.bf.exists('mybloom', 'simon');
|
|
||||||
console.log(`simon ${simonExists ? 'may' : 'does not'} exist in the Bloom Filter.`);
|
|
||||||
|
|
||||||
// Check whether multiple members exist with the BF.MEXISTS command:
|
|
||||||
const [ lanceExists, leibaleExists ] = await client.bf.mExists('mybloom', [
|
|
||||||
'lance',
|
|
||||||
'leibale'
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log(`lance ${lanceExists ? 'may' : 'does not'} exist in the Bloom Filter.`);
|
|
||||||
console.log(`leibale ${leibaleExists ? 'may' : 'does not'} exist in the Bloom Filter.`);
|
|
||||||
|
|
||||||
// Get stats for the Bloom Filter with the BF.INFO command:
|
|
||||||
const info = await client.bf.info('mybloom');
|
|
||||||
// info looks like this:
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// capacity: 1000,
|
|
||||||
// size: 1531,
|
|
||||||
// numberOfFilters: 1,
|
|
||||||
// numberOfInsertedItems: 12,
|
|
||||||
// expansionRate: 2
|
|
||||||
// }
|
|
||||||
console.log(info);
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bloomFilter();
|
// Add items to Bloom Filter individually with BF.ADD command.
|
||||||
|
// https://redis.io/commands/bf.add/
|
||||||
|
await Promise.all([
|
||||||
|
client.bf.add('mybloom', 'leibale'),
|
||||||
|
client.bf.add('mybloom', 'simon'),
|
||||||
|
client.bf.add('mybloom', 'guy'),
|
||||||
|
client.bf.add('mybloom', 'suze'),
|
||||||
|
client.bf.add('mybloom', 'brian'),
|
||||||
|
client.bf.add('mybloom', 'steve'),
|
||||||
|
client.bf.add('mybloom', 'kyle'),
|
||||||
|
client.bf.add('mybloom', 'josefin'),
|
||||||
|
client.bf.add('mybloom', 'alex'),
|
||||||
|
client.bf.add('mybloom', 'nava'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Add multiple items to Bloom Filter at once with BF.MADD command.
|
||||||
|
// https://redis.io/commands/bf.madd/
|
||||||
|
await client.bf.mAdd('mybloom', [
|
||||||
|
'kaitlyn',
|
||||||
|
'rachel'
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log('Added members to Bloom Filter.');
|
||||||
|
|
||||||
|
// Check whether a member exists with the BF.EXISTS command.
|
||||||
|
// https://redis.io/commands/bf.exists/
|
||||||
|
const simonExists = await client.bf.exists('mybloom', 'simon');
|
||||||
|
console.log(`simon ${simonExists ? 'may' : 'does not'} exist in the Bloom Filter.`);
|
||||||
|
|
||||||
|
// Check whether multiple members exist with the BF.MEXISTS command.
|
||||||
|
// https://redis.io/commands/bf.mexists/
|
||||||
|
const [ lanceExists, leibaleExists ] = await client.bf.mExists('mybloom', [
|
||||||
|
'lance',
|
||||||
|
'leibale'
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(`lance ${lanceExists ? 'may' : 'does not'} exist in the Bloom Filter.`);
|
||||||
|
console.log(`leibale ${leibaleExists ? 'may' : 'does not'} exist in the Bloom Filter.`);
|
||||||
|
|
||||||
|
// Get stats for the Bloom Filter with the BF.INFO command.
|
||||||
|
// https://redis.io/commands/bf.info/
|
||||||
|
const info = await client.bf.info('mybloom');
|
||||||
|
// info looks like this:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// capacity: 1000,
|
||||||
|
// size: 1531,
|
||||||
|
// numberOfFilters: 1,
|
||||||
|
// numberOfInsertedItems: 12,
|
||||||
|
// expansionRate: 2
|
||||||
|
// }
|
||||||
|
console.log(info);
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -3,28 +3,23 @@
|
|||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function commandWithModifiers() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
await client.del('mykey');
|
await client.del('mykey');
|
||||||
|
|
||||||
let result = await client.set('mykey', 'myvalue', {
|
let result = await client.set('mykey', 'myvalue', {
|
||||||
EX: 60,
|
EX: 60,
|
||||||
GET: true
|
GET: true
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(result); //nil
|
console.log(result); //null
|
||||||
|
|
||||||
result = await client.set('mykey', 'newvalue', {
|
result = await client.set('mykey', 'newvalue', {
|
||||||
EX: 60,
|
EX: 60,
|
||||||
GET: true
|
GET: true
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(result); //myvalue
|
console.log(result); //myvalue
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
commandWithModifiers();
|
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -7,24 +7,20 @@
|
|||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function connectWithACLUser() {
|
const client = createClient({
|
||||||
const client = createClient({
|
url: 'redis://testuser:testpassword@127.0.0.1:6379'
|
||||||
url: 'redis://testuser:testpassword@127.0.0.1:6379'
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Returns PONG
|
// Returns PONG
|
||||||
console.log(`Response from PING command: ${await client.ping()}`);
|
console.log(`Response from PING command: ${await client.ping()}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// This will error as this user is not allowed to run this command...
|
// This will error as this user is not allowed to run this command...
|
||||||
console.log(`Response from GET command: ${await client.get('somekey')}`);
|
console.log(`Response from GET command: ${await client.get('somekey')}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`GET command failed: ${e.message}`);
|
console.log(`GET command failed: ${e.message}`);
|
||||||
}
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connectWithACLUser();
|
await client.quit();
|
||||||
|
@@ -1,83 +1,80 @@
|
|||||||
// This example demonstrates the use of the Count-Min Sketch
|
// This example demonstrates the use of the Count-Min Sketch
|
||||||
// in the RedisBloom module (https://redisbloom.io/)
|
// in the RedisBloom module (https://redis.io/docs/stack/bloom/)
|
||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function countMinSketch() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Delete any pre-existing Count-Min Sketch.
|
// Delete any pre-existing Count-Min Sketch.
|
||||||
await client.del('mycms');
|
await client.del('mycms');
|
||||||
|
|
||||||
// Initialize a Count-Min Sketch with error rate and probability:
|
// Initialize a Count-Min Sketch with error rate and probability:
|
||||||
// https://oss.redis.com/redisbloom/CountMinSketch_Commands/#cmsinitbyprob
|
// https://redis.io/commands/cms.initbyprob/
|
||||||
try {
|
try {
|
||||||
await client.cms.initByProb('mycms', 0.001, 0.01);
|
await client.cms.initByProb('mycms', 0.001, 0.01);
|
||||||
console.log('Initialized Count-Min Sketch.');
|
console.log('Reserved Count Min Sketch.');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Error, maybe RedisBloom is not installed?:');
|
console.log('Error, maybe RedisBloom is not installed?:');
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
|
||||||
|
|
||||||
const teamMembers = [
|
|
||||||
'leibale',
|
|
||||||
'simon',
|
|
||||||
'guy',
|
|
||||||
'suze',
|
|
||||||
'brian',
|
|
||||||
'steve',
|
|
||||||
'kyleb',
|
|
||||||
'kyleo',
|
|
||||||
'josefin',
|
|
||||||
'alex',
|
|
||||||
'nava',
|
|
||||||
'lance',
|
|
||||||
'rachel',
|
|
||||||
'kaitlyn'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Store actual counts for comparison with CMS.
|
|
||||||
let actualCounts = {};
|
|
||||||
|
|
||||||
// Randomly emit a team member and count them with the CMS.
|
|
||||||
for (let n = 0; n < 1000; n++) {
|
|
||||||
const teamMember = teamMembers[Math.floor(Math.random() * teamMembers.length)];
|
|
||||||
await client.cms.incrBy('mycms', {
|
|
||||||
item: teamMember,
|
|
||||||
incrementBy: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
actualCounts[teamMember] = actualCounts[teamMember] ? actualCounts[teamMember] + 1 : 1;
|
|
||||||
|
|
||||||
console.log(`Incremented score for ${teamMember}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get count estimate for some team members:
|
|
||||||
// https://oss.redis.com/redisbloom/CountMinSketch_Commands/#cmsquery
|
|
||||||
const [ alexCount, rachelCount ] = await client.cms.query('mycms', [
|
|
||||||
'simon',
|
|
||||||
'lance'
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log(`Count estimate for alex: ${alexCount} (actual ${actualCounts.alex}).`);
|
|
||||||
console.log(`Count estimate for rachel: ${rachelCount} (actual ${actualCounts.rachel}).`);
|
|
||||||
|
|
||||||
// Get overall information about the Count-Min Sketch:
|
|
||||||
// https://oss.redis.com/redisbloom/CountMinSketch_Commands/#cmsinfo
|
|
||||||
const info = await client.cms.info('mycms');
|
|
||||||
console.log('Count-Min Sketch info:');
|
|
||||||
|
|
||||||
// info looks like this:
|
|
||||||
// {
|
|
||||||
// width: 2000,
|
|
||||||
// depth: 7,
|
|
||||||
// count: 1000
|
|
||||||
// }
|
|
||||||
console.log(info);
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
countMinSketch();
|
const teamMembers = [
|
||||||
|
'leibale',
|
||||||
|
'simon',
|
||||||
|
'guy',
|
||||||
|
'suze',
|
||||||
|
'brian',
|
||||||
|
'steve',
|
||||||
|
'kyleb',
|
||||||
|
'kyleo',
|
||||||
|
'josefin',
|
||||||
|
'alex',
|
||||||
|
'nava',
|
||||||
|
'lance',
|
||||||
|
'rachel',
|
||||||
|
'kaitlyn'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Store actual counts for comparison with CMS.
|
||||||
|
let actualCounts = {};
|
||||||
|
|
||||||
|
// Randomly emit a team member and count them with the CMS.
|
||||||
|
// https://redis.io/commands/cms.incrby/
|
||||||
|
for (let n = 0; n < 1000; n++) {
|
||||||
|
const teamMember = teamMembers[Math.floor(Math.random() * teamMembers.length)];
|
||||||
|
await client.cms.incrBy('mycms', {
|
||||||
|
item: teamMember,
|
||||||
|
incrementBy: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
actualCounts[teamMember] = actualCounts[teamMember] ? actualCounts[teamMember] + 1 : 1;
|
||||||
|
|
||||||
|
console.log(`Incremented score for ${teamMember}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get count estimate for some team members:
|
||||||
|
// https://redis.io/commands/cms.query/
|
||||||
|
const [ alexCount, rachelCount ] = await client.cms.query('mycms', [
|
||||||
|
'alex',
|
||||||
|
'rachel'
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(`Count estimate for alex: ${alexCount} (actual ${actualCounts.alex}).`);
|
||||||
|
console.log(`Count estimate for rachel: ${rachelCount} (actual ${actualCounts.rachel}).`);
|
||||||
|
|
||||||
|
// Get overall information about the Count-Min Sketch:
|
||||||
|
// https://redis.io/commands/cms.info/
|
||||||
|
const info = await client.cms.info('mycms');
|
||||||
|
console.log('Count-Min Sketch info:');
|
||||||
|
|
||||||
|
// info looks like this:
|
||||||
|
// {
|
||||||
|
// width: 2000,
|
||||||
|
// depth: 7,
|
||||||
|
// count: 1000
|
||||||
|
// }
|
||||||
|
console.log(info);
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -1,81 +1,79 @@
|
|||||||
// This example demonstrates the use of the Cuckoo Filter
|
// This example demonstrates the use of the Cuckoo Filter
|
||||||
// in the RedisBloom module (https://redisbloom.io/)
|
// in the RedisBloom module (https://redis.io/docs/stack/bloom/)
|
||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function cuckooFilter() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Delete any pre-existing Cuckoo Filter.
|
// Delete any pre-existing Cuckoo Filter.
|
||||||
await client.del('mycuckoo');
|
await client.del('mycuckoo');
|
||||||
|
|
||||||
// Reserve a Cuckoo Filter with a capacity of 10000 items.
|
// Reserve a Cuckoo Filter with a capacity of 10000 items.
|
||||||
// https://oss.redis.com/redisbloom/Cuckoo_Commands/#cfreserve
|
// https://redis.io/commands/cf.reserve/
|
||||||
try {
|
try {
|
||||||
await client.cf.reserve('mycuckoo', 10000);
|
await client.cf.reserve('mycuckoo', 10000);
|
||||||
console.log('Reserved Cuckoo Filter.');
|
console.log('Reserved Cuckoo Filter.');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Error, maybe RedisBloom is not installed?:');
|
console.log('Error, maybe RedisBloom is not installed?:');
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
|
||||||
|
|
||||||
// Add items to Cuckoo Filter individually with CF.ADD command.
|
|
||||||
https://oss.redis.com/redisbloom/Cuckoo_Commands/#cfadd
|
|
||||||
await Promise.all([
|
|
||||||
client.cf.add('mycuckoo', 'leibale'),
|
|
||||||
client.cf.add('mycuckoo', 'simon'),
|
|
||||||
client.cf.add('mycuckoo', 'guy'),
|
|
||||||
client.cf.add('mycuckoo', 'suze'),
|
|
||||||
client.cf.add('mycuckoo', 'brian'),
|
|
||||||
client.cf.add('mycuckoo', 'steve'),
|
|
||||||
client.cf.add('mycuckoo', 'kyle'),
|
|
||||||
client.cf.add('mycuckoo', 'josefin'),
|
|
||||||
client.cf.add('mycuckoo', 'alex'),
|
|
||||||
client.cf.add('mycuckoo', 'nava'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Add items to the Cuckoo Filter only if they don't exist in it...
|
|
||||||
// https://oss.redis.com/redisbloom/Cuckoo_Commands/#cfaddnx
|
|
||||||
const nxReply = await Promise.all([
|
|
||||||
client.cf.addNX('mycuckoo', 'kaitlyn'), // New
|
|
||||||
client.cf.addNX('mycuckoo', 'rachel'), // New
|
|
||||||
client.cf.addNX('mycuckoo', 'brian') // Previously added
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log('Added members to Cuckoo Filter.');
|
|
||||||
console.log('nxReply:');
|
|
||||||
|
|
||||||
// nxReply looks like this:
|
|
||||||
// [
|
|
||||||
// true,
|
|
||||||
// true,
|
|
||||||
// false
|
|
||||||
// ]
|
|
||||||
console.log(nxReply);
|
|
||||||
|
|
||||||
// Check whether a member exists with the CF.EXISTS command.
|
|
||||||
const simonExists = await client.bf.exists('mycuckoo', 'simon');
|
|
||||||
console.log(`simon ${simonExists ? 'may' : 'does not'} exist in the Cuckoo Filter.`);
|
|
||||||
|
|
||||||
// Get stats for the Cuckoo Filter with the CF.INFO command:
|
|
||||||
const info = await client.cf.info('mycuckoo');
|
|
||||||
|
|
||||||
// info looks like this:
|
|
||||||
// {
|
|
||||||
// size: 16440,
|
|
||||||
// numberOfBuckets: 8192,
|
|
||||||
// numberOfFilters: 1,
|
|
||||||
// numberOfInsertedItems: 12,
|
|
||||||
// numberOfDeletedItems: 0,
|
|
||||||
// bucketSize: 2,
|
|
||||||
// expansionRate: 1,
|
|
||||||
// maxIteration: 20
|
|
||||||
// }
|
|
||||||
console.log(info);
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cuckooFilter();
|
// Add items to Cuckoo Filter individually with CF.ADD command.
|
||||||
|
// https://redis.io/commands/cf.add/
|
||||||
|
await Promise.all([
|
||||||
|
client.cf.add('mycuckoo', 'leibale'),
|
||||||
|
client.cf.add('mycuckoo', 'simon'),
|
||||||
|
client.cf.add('mycuckoo', 'guy'),
|
||||||
|
client.cf.add('mycuckoo', 'suze'),
|
||||||
|
client.cf.add('mycuckoo', 'brian'),
|
||||||
|
client.cf.add('mycuckoo', 'steve'),
|
||||||
|
client.cf.add('mycuckoo', 'kyle'),
|
||||||
|
client.cf.add('mycuckoo', 'josefin'),
|
||||||
|
client.cf.add('mycuckoo', 'alex'),
|
||||||
|
client.cf.add('mycuckoo', 'nava'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Add items to the Cuckoo Filter only if they don't exist in it...
|
||||||
|
// https://redis.io/commands/cf.addnx/
|
||||||
|
const nxReply = await Promise.all([
|
||||||
|
client.cf.addNX('mycuckoo', 'kaitlyn'), // New
|
||||||
|
client.cf.addNX('mycuckoo', 'rachel'), // New
|
||||||
|
client.cf.addNX('mycuckoo', 'brian') // Previously added
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log('Added members to Cuckoo Filter.');
|
||||||
|
console.log('nxReply:');
|
||||||
|
|
||||||
|
// nxReply looks like this:
|
||||||
|
// [
|
||||||
|
// true,
|
||||||
|
// true,
|
||||||
|
// false
|
||||||
|
// ]
|
||||||
|
console.log(nxReply);
|
||||||
|
|
||||||
|
// Check whether a member exists with the CF.EXISTS command.
|
||||||
|
// https://redis.io/commands/cf.exists/
|
||||||
|
const simonExists = await client.bf.exists('mycuckoo', 'simon');
|
||||||
|
console.log(`simon ${simonExists ? 'may' : 'does not'} exist in the Cuckoo Filter.`);
|
||||||
|
|
||||||
|
// Get stats for the Cuckoo Filter with the CF.INFO command:
|
||||||
|
// https://redis.io/commands/cf.info/
|
||||||
|
const info = await client.cf.info('mycuckoo');
|
||||||
|
|
||||||
|
// info looks like this:
|
||||||
|
// {
|
||||||
|
// size: 16440,
|
||||||
|
// numberOfBuckets: 8192,
|
||||||
|
// numberOfFilters: 1,
|
||||||
|
// numberOfInsertedItems: 12,
|
||||||
|
// numberOfDeletedItems: 0,
|
||||||
|
// bucketSize: 2,
|
||||||
|
// expansionRate: 1,
|
||||||
|
// maxIteration: 20
|
||||||
|
// }
|
||||||
|
console.log(info);
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -2,15 +2,11 @@
|
|||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function getServerTime() {
|
const client = createClient();
|
||||||
const client = createClient();
|
await client.connect();
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
const serverTime = await client.time();
|
const serverTime = await client.time();
|
||||||
// 2022-02-25T12:57:40.000Z { microseconds: 351346 }
|
// 2022-02-25T12:57:40.000Z { microseconds: 351346 }
|
||||||
console.log(serverTime);
|
console.log(serverTime);
|
||||||
|
|
||||||
await client.quit();
|
await client.quit();
|
||||||
}
|
|
||||||
|
|
||||||
getServerTime();
|
|
||||||
|
@@ -3,29 +3,25 @@
|
|||||||
|
|
||||||
import { createClient, defineScript } from 'redis';
|
import { createClient, defineScript } from 'redis';
|
||||||
|
|
||||||
async function luaMultiIncr() {
|
const client = createClient({
|
||||||
const client = createClient({
|
scripts: {
|
||||||
scripts: {
|
mincr: defineScript({
|
||||||
mincr: defineScript({
|
NUMBER_OF_KEYS: 2,
|
||||||
NUMBER_OF_KEYS: 2,
|
SCRIPT:
|
||||||
SCRIPT:
|
'return {' +
|
||||||
'return {' +
|
'redis.pcall("INCRBY", KEYS[1], ARGV[1]),' +
|
||||||
'redis.pcall("INCRBY", KEYS[1], ARGV[1]),' +
|
'redis.pcall("INCRBY", KEYS[2], ARGV[1])' +
|
||||||
'redis.pcall("INCRBY", KEYS[2], ARGV[1])' +
|
'}',
|
||||||
'}',
|
transformArguments(key1, key2, increment) {
|
||||||
transformArguments(key1, key2, increment) {
|
return [key1, key2, increment.toString()];
|
||||||
return [key1, key2, increment.toString()];
|
},
|
||||||
},
|
}),
|
||||||
}),
|
},
|
||||||
},
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
await client.set('mykey', '5');
|
await client.set('mykey', '5');
|
||||||
console.log(await client.mincr('mykey', 'myotherkey', 10)); // [ 15, 10 ]
|
console.log(await client.mincr('mykey', 'myotherkey', 10)); // [ 15, 10 ]
|
||||||
|
|
||||||
await client.quit();
|
await client.quit();
|
||||||
}
|
|
||||||
|
|
||||||
luaMultiIncr();
|
|
||||||
|
@@ -2,80 +2,75 @@
|
|||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function managingJSON() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
await client.del('noderedis:jsondata');
|
await client.del('noderedis:jsondata');
|
||||||
|
|
||||||
// Store a JSON object...
|
// Store a JSON object...
|
||||||
await client.json.set('noderedis:jsondata', '$', {
|
await client.json.set('noderedis:jsondata', '$', {
|
||||||
name: 'Roberta McDonald',
|
name: 'Roberta McDonald',
|
||||||
pets: [
|
pets: [
|
||||||
{
|
{
|
||||||
name: 'Fluffy',
|
name: 'Fluffy',
|
||||||
species: 'dog',
|
species: 'dog',
|
||||||
age: 5,
|
age: 5,
|
||||||
isMammal: true
|
isMammal: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Rex',
|
name: 'Rex',
|
||||||
species: 'dog',
|
species: 'dog',
|
||||||
age: 3,
|
age: 3,
|
||||||
isMammal: true
|
isMammal: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Goldie',
|
name: 'Goldie',
|
||||||
species: 'fish',
|
species: 'fish',
|
||||||
age: 2,
|
age: 2,
|
||||||
isMammal: false
|
isMammal: false
|
||||||
}
|
|
||||||
],
|
|
||||||
address: {
|
|
||||||
number: 99,
|
|
||||||
street: 'Main Street',
|
|
||||||
city: 'Springfield',
|
|
||||||
state: 'OH',
|
|
||||||
country: 'USA'
|
|
||||||
}
|
}
|
||||||
});
|
],
|
||||||
|
address: {
|
||||||
|
number: 99,
|
||||||
|
street: 'Main Street',
|
||||||
|
city: 'Springfield',
|
||||||
|
state: 'OH',
|
||||||
|
country: 'USA'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Retrieve the name and age of the second pet in the pets array.
|
// Retrieve the name and age of the second pet in the pets array.
|
||||||
let results = await client.json.get('noderedis:jsondata', {
|
let results = await client.json.get('noderedis:jsondata', {
|
||||||
path: [
|
path: [
|
||||||
'.pets[1].name',
|
'$.pets[1].name',
|
||||||
'.pets[1].age'
|
'$.pets[1].age'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// { '.pets[1].name': 'Rex', '.pets[1].age': 3 }
|
// { '$.pets[1].name': [ 'Rex' ], '$.pets[1].age': [ 3 ] }
|
||||||
console.log(results);
|
console.log(results);
|
||||||
|
|
||||||
// Goldie had a birthday, increment the age...
|
// Goldie had a birthday, increment the age...
|
||||||
await client.json.numIncrBy('noderedis:jsondata', '.pets[2].age', 1);
|
await client.json.numIncrBy('noderedis:jsondata', '$.pets[2].age', 1);
|
||||||
results = await client.json.get('noderedis:jsondata', {
|
results = await client.json.get('noderedis:jsondata', {
|
||||||
path: '.pets[2].age'
|
path: '$.pets[2].age'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Goldie is 3 years old now.
|
// Goldie is 3 years old now.
|
||||||
console.log(`Goldie is ${JSON.stringify(results)} years old now.`);
|
console.log(`Goldie is ${JSON.stringify(results[0])} years old now.`);
|
||||||
|
|
||||||
// Add a new pet...
|
// Add a new pet...
|
||||||
await client.json.arrAppend('noderedis:jsondata', '.pets', {
|
await client.json.arrAppend('noderedis:jsondata', '$.pets', {
|
||||||
name: 'Robin',
|
name: 'Robin',
|
||||||
species: 'bird',
|
species: 'bird',
|
||||||
isMammal: false,
|
isMammal: false,
|
||||||
age: 1
|
age: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
// How many pets do we have now?
|
// How many pets do we have now?
|
||||||
const numPets = await client.json.arrLen('noderedis:jsondata', '.pets');
|
const numPets = await client.json.arrLen('noderedis:jsondata', '$.pets');
|
||||||
|
|
||||||
// We now have 4 pets.
|
// We now have 4 pets.
|
||||||
console.log(`We now have ${numPets} pets.`);
|
console.log(`We now have ${numPets} pets.`);
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
managingJSON();
|
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -3,89 +3,86 @@
|
|||||||
|
|
||||||
import { createClient, SchemaFieldTypes } from 'redis';
|
import { createClient, SchemaFieldTypes } from 'redis';
|
||||||
|
|
||||||
async function searchHashes() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Create an index...
|
// Create an index...
|
||||||
try {
|
try {
|
||||||
// Documentation: https://oss.redis.com/redisearch/Commands/#ftcreate
|
// Documentation: https://redis.io/commands/ft.create/
|
||||||
await client.ft.create('idx:animals', {
|
await client.ft.create('idx:animals', {
|
||||||
name: {
|
name: {
|
||||||
type: SchemaFieldTypes.TEXT,
|
type: SchemaFieldTypes.TEXT,
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
species: SchemaFieldTypes.TAG,
|
species: SchemaFieldTypes.TAG,
|
||||||
age: SchemaFieldTypes.NUMERIC
|
age: SchemaFieldTypes.NUMERIC
|
||||||
}, {
|
}, {
|
||||||
ON: 'HASH',
|
ON: 'HASH',
|
||||||
PREFIX: 'noderedis:animals'
|
PREFIX: 'noderedis:animals'
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === 'Index already exists') {
|
if (e.message === 'Index already exists') {
|
||||||
console.log('Index exists already, skipped creation.');
|
console.log('Index exists already, skipped creation.');
|
||||||
} else {
|
} else {
|
||||||
// Something went wrong, perhaps RediSearch isn't installed...
|
// Something went wrong, perhaps RediSearch isn't installed...
|
||||||
console.error(e);
|
console.error(e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add some sample data...
|
|
||||||
await Promise.all([
|
|
||||||
client.hSet('noderedis:animals:1', {name: 'Fluffy', species: 'cat', age: 3}),
|
|
||||||
client.hSet('noderedis:animals:2', {name: 'Ginger', species: 'cat', age: 4}),
|
|
||||||
client.hSet('noderedis:animals:3', {name: 'Rover', species: 'dog', age: 9}),
|
|
||||||
client.hSet('noderedis:animals:4', {name: 'Fido', species: 'dog', age: 7})
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Perform a search query, find all the dogs... sort by age, descending.
|
|
||||||
// Documentation: https://oss.redis.com/redisearch/Commands/#ftsearch
|
|
||||||
// Query syntax: https://oss.redis.com/redisearch/Query_Syntax/
|
|
||||||
const results = await client.ft.search(
|
|
||||||
'idx:animals',
|
|
||||||
'@species:{dog}',
|
|
||||||
{
|
|
||||||
SORTBY: {
|
|
||||||
BY: 'age',
|
|
||||||
DIRECTION: 'DESC' // or 'ASC' (default if DIRECTION is not present)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// results:
|
|
||||||
// {
|
|
||||||
// total: 2,
|
|
||||||
// documents: [
|
|
||||||
// {
|
|
||||||
// id: 'noderedis:animals:3',
|
|
||||||
// value: {
|
|
||||||
// age: '9',
|
|
||||||
// name: 'Rover',
|
|
||||||
// species: 'dog'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// id: 'noderedis:animals:4',
|
|
||||||
// value: {
|
|
||||||
// age: '7',
|
|
||||||
// name: 'Fido',
|
|
||||||
// species: 'dog'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
|
|
||||||
console.log(`Results found: ${results.total}.`);
|
|
||||||
|
|
||||||
for (const doc of results.documents) {
|
|
||||||
// noderedis:animals:3: Rover, 9 years old.
|
|
||||||
// noderedis:animals:4: Fido, 7 years old.
|
|
||||||
console.log(`${doc.id}: ${doc.value.name}, ${doc.value.age} years old.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
searchHashes();
|
// Add some sample data...
|
||||||
|
// https://redis.io/commands/hset/
|
||||||
|
await Promise.all([
|
||||||
|
client.hSet('noderedis:animals:1', {name: 'Fluffy', species: 'cat', age: 3}),
|
||||||
|
client.hSet('noderedis:animals:2', {name: 'Ginger', species: 'cat', age: 4}),
|
||||||
|
client.hSet('noderedis:animals:3', {name: 'Rover', species: 'dog', age: 9}),
|
||||||
|
client.hSet('noderedis:animals:4', {name: 'Fido', species: 'dog', age: 7})
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Perform a search query, find all the dogs... sort by age, descending.
|
||||||
|
// Documentation: https://redis.io/commands/ft.search/
|
||||||
|
// Query syntax: https://redis.io/docs/stack/search/reference/query_syntax/
|
||||||
|
const results = await client.ft.search(
|
||||||
|
'idx:animals',
|
||||||
|
'@species:{dog}',
|
||||||
|
{
|
||||||
|
SORTBY: {
|
||||||
|
BY: 'age',
|
||||||
|
DIRECTION: 'DESC' // or 'ASC (default if DIRECTION is not present)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// results:
|
||||||
|
// {
|
||||||
|
// total: 2,
|
||||||
|
// documents: [
|
||||||
|
// {
|
||||||
|
// id: 'noderedis:animals:3',
|
||||||
|
// value: {
|
||||||
|
// name: 'Rover',
|
||||||
|
// species: 'dog',
|
||||||
|
// age: '9'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// id: 'noderedis:animals:4',
|
||||||
|
// value: {
|
||||||
|
// name: 'Fido',
|
||||||
|
// species: 'dog',
|
||||||
|
// age: '7'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log(`Results found: ${results.total}.`);
|
||||||
|
|
||||||
|
for (const doc of results.documents) {
|
||||||
|
// noderedis:animals:3: Rover, 9 years old.
|
||||||
|
// noderedis:animals:4: Fido, 7 years old.
|
||||||
|
console.log(`${doc.id}: ${doc.value.name}, ${doc.value.age} years old.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -1,147 +1,148 @@
|
|||||||
// This example demonstrates how to use RediSearch and RedisJSON together.
|
// This example demonstrates how to use RediSearch and RedisJSON together.
|
||||||
|
// Requires both the RediSearch and RedisJSON modules:
|
||||||
|
// https://redis.io/docs/stack/search/
|
||||||
|
// https://redis.io/docs/stack/json/
|
||||||
|
|
||||||
import { createClient, SchemaFieldTypes, AggregateGroupByReducers, AggregateSteps } from 'redis';
|
import { createClient, SchemaFieldTypes, AggregateGroupByReducers, AggregateSteps } from 'redis';
|
||||||
|
|
||||||
async function searchJSON() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Create an index.
|
// Create an index.
|
||||||
try {
|
// https://redis.io/commands/ft.create/
|
||||||
await client.ft.create('idx:users', {
|
try {
|
||||||
'$.name': {
|
await client.ft.create('idx:users', {
|
||||||
type: SchemaFieldTypes.TEXT,
|
'$.name': {
|
||||||
SORTABLE: 'UNF'
|
type: SchemaFieldTypes.TEXT,
|
||||||
},
|
SORTABLE: 'UNF'
|
||||||
'$.age': {
|
},
|
||||||
type: SchemaFieldTypes.NUMERIC,
|
'$.age': {
|
||||||
AS: 'age'
|
type: SchemaFieldTypes.NUMERIC,
|
||||||
},
|
AS: 'age'
|
||||||
'$.coins': {
|
},
|
||||||
type: SchemaFieldTypes.NUMERIC,
|
'$.coins': {
|
||||||
AS: 'coins'
|
type: SchemaFieldTypes.NUMERIC,
|
||||||
},
|
AS: 'coins'
|
||||||
'$.email': {
|
},
|
||||||
type: SchemaFieldTypes.TAG,
|
'$.email': {
|
||||||
AS: 'email'
|
type: SchemaFieldTypes.TAG,
|
||||||
}
|
AS: 'email'
|
||||||
}, {
|
|
||||||
ON: 'JSON',
|
|
||||||
PREFIX: 'noderedis:users'
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if (e.message === 'Index already exists') {
|
|
||||||
console.log('Index exists already, skipped creation.');
|
|
||||||
} else {
|
|
||||||
// Something went wrong, perhaps RediSearch isn't installed...
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
ON: 'JSON',
|
||||||
|
PREFIX: 'noderedis:users'
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message === 'Index already exists') {
|
||||||
|
console.log('Index exists already, skipped creation.');
|
||||||
|
} else {
|
||||||
|
// Something went wrong, perhaps RediSearch isn't installed...
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add some users.
|
|
||||||
await Promise.all([
|
|
||||||
client.json.set('noderedis:users:1', '$', {
|
|
||||||
name: 'Alice',
|
|
||||||
age: 32,
|
|
||||||
coins: 100,
|
|
||||||
email: 'alice@nonexist.com'
|
|
||||||
}),
|
|
||||||
client.json.set('noderedis:users:2', '$', {
|
|
||||||
name: 'Bob',
|
|
||||||
age: 23,
|
|
||||||
coins: 15,
|
|
||||||
email: 'bob@somewhere.gov'
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Search all users under 30
|
|
||||||
console.log('Users under 30 years old:');
|
|
||||||
console.log(
|
|
||||||
// https://oss.redis.com/redisearch/Commands/#ftsearch
|
|
||||||
JSON.stringify(
|
|
||||||
await client.ft.search('idx:users', '@age:[0 30]'),
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// {
|
|
||||||
// "total": 1,
|
|
||||||
// "documents": [
|
|
||||||
// {
|
|
||||||
// "id": "noderedis:users:2",
|
|
||||||
// "value": {
|
|
||||||
// "name": "Bob",
|
|
||||||
// "age": 23,
|
|
||||||
// "coins": 15,
|
|
||||||
// "email": "bob@somewhere.gov"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Find a user by email - note we need to escape . and @ characters
|
|
||||||
// in the email address. This applies for other punctuation too.
|
|
||||||
// https://oss.redis.com/redisearch/Tags/#including_punctuation_in_tags
|
|
||||||
console.log('Users with email "bob@somewhere.gov":');
|
|
||||||
const emailAddress = 'bob@somewhere.gov'.replace(/[.@]/g, '\\$&');
|
|
||||||
console.log(
|
|
||||||
JSON.stringify(
|
|
||||||
await client.ft.search('idx:users', `@email:{${emailAddress}}`),
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// {
|
|
||||||
// "total": 1,
|
|
||||||
// "documents": [
|
|
||||||
// {
|
|
||||||
// "id": "noderedis:users:2",
|
|
||||||
// "value": {
|
|
||||||
// "name": "Bob",
|
|
||||||
// "age": 23,
|
|
||||||
// "coins": 15,
|
|
||||||
// "email": "bob@somewhere.gov"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Some aggregrations, what's the average age and total number of coins...
|
|
||||||
// https://oss.redis.com/redisearch/Commands/#ftaggregate
|
|
||||||
console.log('Aggregation Demo:');
|
|
||||||
console.log(
|
|
||||||
JSON.stringify(
|
|
||||||
await client.ft.aggregate('idx:users', '*', {
|
|
||||||
STEPS: [{
|
|
||||||
type: AggregateSteps.GROUPBY,
|
|
||||||
REDUCE: [{
|
|
||||||
type: AggregateGroupByReducers.AVG,
|
|
||||||
property: 'age',
|
|
||||||
AS: 'averageAge'
|
|
||||||
}, {
|
|
||||||
type: AggregateGroupByReducers.SUM,
|
|
||||||
property: 'coins',
|
|
||||||
AS: 'totalCoins'
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}),
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// {
|
|
||||||
// "total": 1,
|
|
||||||
// "results": [
|
|
||||||
// {
|
|
||||||
// "averageAge": "27.5",
|
|
||||||
// "totalCoins": "115"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
searchJSON();
|
// Add some users.
|
||||||
|
// https://redis.io/commands/json.set/
|
||||||
|
await Promise.all([
|
||||||
|
client.json.set('noderedis:users:1', '$', {
|
||||||
|
name: 'Alice',
|
||||||
|
age: 32,
|
||||||
|
coins: 100,
|
||||||
|
email: 'alice@nonexist.com'
|
||||||
|
}),
|
||||||
|
client.json.set('noderedis:users:2', '$', {
|
||||||
|
name: 'Bob',
|
||||||
|
age: 23,
|
||||||
|
coins: 15,
|
||||||
|
email: 'bob@somewhere.gov'
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Search all users under 30
|
||||||
|
console.log('Users under 30 years old:');
|
||||||
|
console.log(
|
||||||
|
// https://redis.io/commands/ft.search/
|
||||||
|
JSON.stringify(
|
||||||
|
await client.ft.search('idx:users', '@age:[0 30]'),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// {
|
||||||
|
// "total": 1,
|
||||||
|
// "documents": [
|
||||||
|
// {
|
||||||
|
// "id": "noderedis:users:2",
|
||||||
|
// "value": {
|
||||||
|
// "name": "Bob",
|
||||||
|
// "age": 23,
|
||||||
|
// "coins": 15,
|
||||||
|
// "email": "bob@somewhere.gov"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Find a user by email - note we need to escape . and @ characters
|
||||||
|
// in the email address. This applies for other punctuation too.
|
||||||
|
// https://redis.io/docs/stack/search/reference/tags/#including-punctuation-in-tags
|
||||||
|
console.log('Users with email "bob@somewhere.gov":');
|
||||||
|
const emailAddress = 'bob@somewhere.gov'.replace(/[.@]/g, '\\$&');
|
||||||
|
console.log(
|
||||||
|
JSON.stringify(
|
||||||
|
await client.ft.search('idx:users', `@email:{${emailAddress}}`),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// {
|
||||||
|
// "total": 1,
|
||||||
|
// "documents": [
|
||||||
|
// {
|
||||||
|
// "id": "noderedis:users:2",
|
||||||
|
// "value": {
|
||||||
|
// "name": "Bob",
|
||||||
|
// "age": 23,
|
||||||
|
// "coins": 15,
|
||||||
|
// "email": "bob@somewhere.gov"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Some aggregrations, what's the average age and total number of coins...
|
||||||
|
// https://redis.io/commands/ft.aggregate/
|
||||||
|
console.log('Aggregation Demo:');
|
||||||
|
console.log(
|
||||||
|
JSON.stringify(
|
||||||
|
await client.ft.aggregate('idx:users', '*', {
|
||||||
|
STEPS: [{
|
||||||
|
type: AggregateSteps.GROUPBY,
|
||||||
|
REDUCE: [{
|
||||||
|
type: AggregateGroupByReducers.AVG,
|
||||||
|
property: 'age',
|
||||||
|
AS: 'averageAge'
|
||||||
|
}, {
|
||||||
|
type: AggregateGroupByReducers.SUM,
|
||||||
|
property: 'coins',
|
||||||
|
AS: 'totalCoins'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// {
|
||||||
|
// "total": 1,
|
||||||
|
// "results": [
|
||||||
|
// {
|
||||||
|
// "averageAge": "27.5",
|
||||||
|
// "totalCoins": "115"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -4,16 +4,12 @@
|
|||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function setScan() {
|
const client = createClient();
|
||||||
const client = createClient();
|
await client.connect();
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
const setName = 'setName';
|
const setName = 'setName';
|
||||||
for await (const member of client.sScanIterator(setName)) {
|
for await (const member of client.sScanIterator(setName)) {
|
||||||
console.log(member);
|
console.log(member);
|
||||||
}
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setScan();
|
await client.quit();
|
||||||
|
@@ -3,33 +3,29 @@
|
|||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function addToSortedSet() {
|
const client = createClient();
|
||||||
const client = createClient();
|
await client.connect();
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
await client.zAdd('mysortedset', [
|
await client.zAdd('mysortedset', [
|
||||||
{
|
{
|
||||||
score: 99,
|
score: 99,
|
||||||
value: 'Ninety Nine'
|
value: 'Ninety Nine'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
score: 100,
|
score: 100,
|
||||||
value: 'One Hundred'
|
value: 'One Hundred'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
score: 101,
|
score: 101,
|
||||||
value: 'One Hundred and One'
|
value: 'One Hundred and One'
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Get all of the values/scores from the sorted set using
|
|
||||||
// the scan approach:
|
|
||||||
// https://redis.io/commands/zscan
|
|
||||||
for await (const memberWithScore of client.zScanIterator('mysortedset')) {
|
|
||||||
console.log(memberWithScore);
|
|
||||||
}
|
}
|
||||||
|
]);
|
||||||
await client.quit();
|
|
||||||
|
// Get all of the values/scores from the sorted set using
|
||||||
|
// the scan approach:
|
||||||
|
// https://redis.io/commands/zscan
|
||||||
|
for await (const memberWithScore of client.zScanIterator('mysortedset')) {
|
||||||
|
console.log(memberWithScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
addToSortedSet();
|
await client.quit();
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
// A sample stream consumer using the blocking variant of XREADGROUP.
|
// A sample stream consumer using the blocking variant of XREADGROUP.
|
||||||
|
// https://redis.io/commands/xreadgroup/
|
||||||
|
|
||||||
// This consumer works in collaboration with other instances of itself
|
// This consumer works in collaboration with other instances of itself
|
||||||
// in the same consumer group such that the group as a whole receives
|
// in the same consumer group such that the group as a whole receives
|
||||||
// every entry from the stream.
|
// every entry from the stream.
|
||||||
@@ -20,85 +22,84 @@
|
|||||||
|
|
||||||
import { createClient, commandOptions } from 'redis';
|
import { createClient, commandOptions } from 'redis';
|
||||||
|
|
||||||
async function streamConsumerGroup() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
if (process.argv.length !== 3) {
|
if (process.argv.length !== 3) {
|
||||||
console.log(`usage: node stream-consumer-group.js <consumerName>`);
|
console.log(`usage: node stream-consumer-group.js <consumerName>`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
|
||||||
|
|
||||||
const consumerName = process.argv[2];
|
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
// Create the consumer group (and stream) if needed...
|
|
||||||
try {
|
|
||||||
await client.xGroupCreate('mystream', 'myconsumergroup', '0', {
|
|
||||||
MKSTREAM: true
|
|
||||||
});
|
|
||||||
console.log('Created consumer group.');
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Consumer group already exists, skipped creation.');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Starting consumer ${consumerName}.`);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
let response = await client.xReadGroup(
|
|
||||||
commandOptions({
|
|
||||||
isolated: true
|
|
||||||
}),
|
|
||||||
'myconsumergroup',
|
|
||||||
consumerName, [
|
|
||||||
// XREADGROUP can read from multiple streams, starting at a
|
|
||||||
// different ID for each...
|
|
||||||
{
|
|
||||||
key: 'mystream',
|
|
||||||
id: '>' // Next entry ID that no consumer in this group has read
|
|
||||||
}
|
|
||||||
], {
|
|
||||||
// Read 1 entry at a time, block for 5 seconds if there are none.
|
|
||||||
COUNT: 1,
|
|
||||||
BLOCK: 5000
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response) {
|
|
||||||
// Response is an array of streams, each containing an array of
|
|
||||||
// entries:
|
|
||||||
//
|
|
||||||
// [
|
|
||||||
// {
|
|
||||||
// "name": "mystream",
|
|
||||||
// "messages": [
|
|
||||||
// {
|
|
||||||
// "id": "1642088708425-0",
|
|
||||||
// "message": {
|
|
||||||
// "num": "999"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
console.log(JSON.stringify(response));
|
|
||||||
|
|
||||||
// Use XACK to acknowledge successful processing of this
|
|
||||||
// stream entry.
|
|
||||||
const entryId = response[0].messages[0].id;
|
|
||||||
await client.xAck('mystream', 'myconsumergroup', entryId);
|
|
||||||
|
|
||||||
console.log(`Acknowledged processing of entry ${entryId}.`);
|
|
||||||
} else {
|
|
||||||
// Response is null, we have read everything that is
|
|
||||||
// in the stream right now...
|
|
||||||
console.log('No new stream entries.');
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
streamConsumerGroup();
|
const consumerName = process.argv[2];
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
// Create the consumer group (and stream) if needed...
|
||||||
|
try {
|
||||||
|
// https://redis.io/commands/xgroup-create/
|
||||||
|
await client.xGroupCreate('mystream', 'myconsumergroup', '0', {
|
||||||
|
MKSTREAM: true
|
||||||
|
});
|
||||||
|
console.log('Created consumer group.');
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Consumer group already exists, skipped creation.');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Starting consumer ${consumerName}.`);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
// https://redis.io/commands/xreadgroup/
|
||||||
|
let response = await client.xReadGroup(
|
||||||
|
commandOptions({
|
||||||
|
isolated: true
|
||||||
|
}),
|
||||||
|
'myconsumergroup',
|
||||||
|
consumerName, [
|
||||||
|
// XREADGROUP can read from multiple streams, starting at a
|
||||||
|
// different ID for each...
|
||||||
|
{
|
||||||
|
key: 'mystream',
|
||||||
|
id: '>' // Next entry ID that no consumer in this group has read
|
||||||
|
}
|
||||||
|
], {
|
||||||
|
// Read 1 entry at a time, block for 5 seconds if there are none.
|
||||||
|
COUNT: 1,
|
||||||
|
BLOCK: 5000
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
// Response is an array of streams, each containing an array of
|
||||||
|
// entries:
|
||||||
|
//
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// "name": "mystream",
|
||||||
|
// "messages": [
|
||||||
|
// {
|
||||||
|
// "id": "1642088708425-0",
|
||||||
|
// "message": {
|
||||||
|
// "num": "999"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
console.log(JSON.stringify(response));
|
||||||
|
|
||||||
|
// Use XACK to acknowledge successful processing of this
|
||||||
|
// stream entry.
|
||||||
|
// https://redis.io/commands/xack/
|
||||||
|
const entryId = response[0].messages[0].id;
|
||||||
|
await client.xAck('mystream', 'myconsumergroup', entryId);
|
||||||
|
|
||||||
|
console.log(`Acknowledged processing of entry ${entryId}.`);
|
||||||
|
} else {
|
||||||
|
// Response is null, we have read everything that is
|
||||||
|
// in the stream right now...
|
||||||
|
console.log('No new stream entries.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,64 +1,61 @@
|
|||||||
// A sample stream consumer using the blocking variant of XREAD.
|
// A sample stream consumer using the blocking variant of XREAD.
|
||||||
|
// https://redis.io/commands/xread/
|
||||||
// This consumes entries from a stream created by stream-producer.js
|
// This consumes entries from a stream created by stream-producer.js
|
||||||
|
|
||||||
import { createClient, commandOptions } from 'redis';
|
import { createClient, commandOptions } from 'redis';
|
||||||
|
|
||||||
async function streamConsumer() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
let currentId = '0-0'; // Start at lowest possible stream ID
|
let currentId = '0-0'; // Start at lowest possible stream ID
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
let response = await client.xRead(
|
let response = await client.xRead(
|
||||||
commandOptions({
|
commandOptions({
|
||||||
isolated: true
|
isolated: true
|
||||||
}), [
|
}), [
|
||||||
// XREAD can read from multiple streams, starting at a
|
// XREAD can read from multiple streams, starting at a
|
||||||
// different ID for each...
|
// different ID for each...
|
||||||
{
|
{
|
||||||
key: 'mystream',
|
key: 'mystream',
|
||||||
id: currentId
|
id: currentId
|
||||||
}
|
|
||||||
], {
|
|
||||||
// Read 1 entry at a time, block for 5 seconds if there are none.
|
|
||||||
COUNT: 1,
|
|
||||||
BLOCK: 5000
|
|
||||||
}
|
}
|
||||||
);
|
], {
|
||||||
|
// Read 1 entry at a time, block for 5 seconds if there are none.
|
||||||
if (response) {
|
COUNT: 1,
|
||||||
// Response is an array of streams, each containing an array of
|
BLOCK: 5000
|
||||||
// entries:
|
|
||||||
// [
|
|
||||||
// {
|
|
||||||
// "name": "mystream",
|
|
||||||
// "messages": [
|
|
||||||
// {
|
|
||||||
// "id": "1642088708425-0",
|
|
||||||
// "message": {
|
|
||||||
// "num": "999"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
console.log(JSON.stringify(response));
|
|
||||||
|
|
||||||
// Get the ID of the first (only) entry returned.
|
|
||||||
currentId = response[0].messages[0].id;
|
|
||||||
console.log(currentId);
|
|
||||||
} else {
|
|
||||||
// Response is null, we have read everything that is
|
|
||||||
// in the stream right now...
|
|
||||||
console.log('No new stream entries.');
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
);
|
||||||
console.error(err);
|
|
||||||
|
if (response) {
|
||||||
|
// Response is an array of streams, each containing an array of
|
||||||
|
// entries:
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// "name": "mystream",
|
||||||
|
// "messages": [
|
||||||
|
// {
|
||||||
|
// "id": "1642088708425-0",
|
||||||
|
// "message": {
|
||||||
|
// "num": "999"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
console.log(JSON.stringify(response));
|
||||||
|
|
||||||
|
// Get the ID of the first (only) entry returned.
|
||||||
|
currentId = response[0].messages[0].id;
|
||||||
|
console.log(currentId);
|
||||||
|
} else {
|
||||||
|
// Response is null, we have read everything that is
|
||||||
|
// in the stream right now...
|
||||||
|
console.log('No new stream entries.');
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
streamConsumer();
|
|
||||||
|
@@ -1,53 +1,50 @@
|
|||||||
// A sample stream producer using XADD.
|
// A sample stream producer using XADD.
|
||||||
|
// https://redis.io/commands/xadd/
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function streamProducer() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
for (let i = 0; i < 10000; i++) {
|
for (let i = 0; i < 10000; i++) {
|
||||||
await client.xAdd(
|
await client.xAdd(
|
||||||
'mystream',
|
'mystream',
|
||||||
'*', // * = Let Redis generate a timestamp ID for this new entry.
|
'*', // * = Let Redis generate a timestamp ID for this new entry.
|
||||||
// Payload to add to the stream:
|
// Payload to add to the stream:
|
||||||
{
|
{
|
||||||
i: i.toString()
|
i: i.toString()
|
||||||
// Other name/value pairs can go here as required...
|
// Other name/value pairs can go here as required...
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Also add to a stream whose length we will cap at approximately
|
||||||
|
// 1000 entries using the MAXLEN trimming strategy:
|
||||||
|
// https://redis.io/commands/xadd/
|
||||||
|
|
||||||
|
await client.xAdd(
|
||||||
|
'mytrimmedstream',
|
||||||
|
'*',
|
||||||
|
// Payload to add to the stream:
|
||||||
|
{
|
||||||
|
i: i.toString()
|
||||||
|
// Other name/value pairs can go here as required...
|
||||||
|
},
|
||||||
|
// Specify a trimming strategy...
|
||||||
|
{
|
||||||
|
TRIM: {
|
||||||
|
strategy: 'MAXLEN', // Trim by length.
|
||||||
|
strategyModifier: '~', // Approximate trimming.
|
||||||
|
threshold: 1000 // Retain around 1000 entries.
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
);
|
||||||
// Also add to a stream whose length we will cap at approximately
|
|
||||||
// 1000 entries using the MAXLEN trimming strategy:
|
|
||||||
// https://redis.io/commands/xadd/
|
|
||||||
|
|
||||||
await client.xAdd(
|
|
||||||
'mytrimmedstream',
|
|
||||||
id, // Re-use the ID from the previous stream.
|
|
||||||
// Payload to add to the stream:
|
|
||||||
{
|
|
||||||
i: i.toString()
|
|
||||||
// Other name/value pairs can go here as required...
|
|
||||||
},
|
|
||||||
// Specify a trimming strategy...
|
|
||||||
{
|
|
||||||
TRIM: {
|
|
||||||
strategy: 'MAXLEN', // Trim by length.
|
|
||||||
strategyModifier: '~', // Approximate trimming.
|
|
||||||
threshold: 1000 // Retain around 1000 entries.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take a look at how many entries are in the streams...
|
|
||||||
// Should be 10000:
|
|
||||||
console.log(`Length of mystream: ${await client.xLen('mystream')}.`);
|
|
||||||
// Should be approximately 1000:
|
|
||||||
console.log(`Length of mytrimmedstream: ${await client.xLen('mytrimmedstream')}.`);
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
streamProducer();
|
// Take a look at how many entries are in the streams...
|
||||||
|
// https://redis.io/commands/xlen/
|
||||||
|
// Should be 10000:
|
||||||
|
console.log(`Length of mystream: ${await client.xLen('mystream')}.`);
|
||||||
|
// Should be approximately 1000:
|
||||||
|
console.log(`Length of mytrimmedstream: ${await client.xLen('mytrimmedstream')}.`);
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
@@ -1,126 +1,122 @@
|
|||||||
// Add data to a Redis TimeSeries and query it.
|
// Add data to a Redis TimeSeries and query it.
|
||||||
// Requires the RedisTimeSeries module: https://redistimeseries.io/
|
// Requires the RedisTimeSeries module: https://redis.io/docs/stack/timeseries/
|
||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
import { TimeSeriesDuplicatePolicies, TimeSeriesEncoding, TimeSeriesAggregationType } from '@redis/time-series';
|
import { TimeSeriesDuplicatePolicies, TimeSeriesEncoding, TimeSeriesAggregationType } from '@redis/time-series';
|
||||||
|
|
||||||
async function timeSeries() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
await client.del('mytimeseries');
|
await client.del('mytimeseries');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create a timeseries
|
// Create a timeseries
|
||||||
// https://oss.redis.com/redistimeseries/commands/#tscreate
|
// https://redis.io/commands/ts.create/
|
||||||
const created = await client.ts.create('mytimeseries', {
|
const created = await client.ts.create('mytimeseries', {
|
||||||
RETENTION: 86400000, // 1 day in milliseconds
|
RETENTION: 86400000, // 1 day in milliseconds
|
||||||
ENCODING: TimeSeriesEncoding.UNCOMPRESSED, // No compression
|
ENCODING: TimeSeriesEncoding.UNCOMPRESSED, // No compression
|
||||||
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.BLOCK // No duplicates
|
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.BLOCK // No duplicates
|
||||||
});
|
});
|
||||||
|
|
||||||
if (created === 'OK') {
|
if (created === 'OK') {
|
||||||
console.log('Created timeseries.');
|
console.log('Created timeseries.');
|
||||||
} else {
|
} else {
|
||||||
console.log('Error creating timeseries :(');
|
console.log('Error creating timeseries :(');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
|
||||||
|
|
||||||
let value = Math.floor(Math.random() * 1000) + 1; // Random data point value
|
|
||||||
let currentTimestamp = 1640995200000; // Jan 1 2022 00:00:00
|
|
||||||
let num = 0;
|
|
||||||
|
|
||||||
while (num < 10000) {
|
|
||||||
// Add a new value to the timeseries, providing our own timestamp:
|
|
||||||
// https://oss.redis.com/redistimeseries/commands/#tsadd
|
|
||||||
await client.ts.add('mytimeseries', currentTimestamp, value);
|
|
||||||
console.log(`Added timestamp ${currentTimestamp}, value ${value}.`);
|
|
||||||
|
|
||||||
num += 1;
|
|
||||||
value = Math.floor(Math.random() * 1000) + 1; // Get another random value
|
|
||||||
currentTimestamp += 1000; // Move on one second.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add multiple values to the timeseries in round trip to the server:
|
|
||||||
// https://oss.redis.com/redistimeseries/commands/#tsmadd
|
|
||||||
const response = await client.ts.mAdd([{
|
|
||||||
key: 'mytimeseries',
|
|
||||||
timestamp: currentTimestamp + 60000,
|
|
||||||
value: Math.floor(Math.random() * 1000) + 1
|
|
||||||
}, {
|
|
||||||
key: 'mytimeseries',
|
|
||||||
timestamp: currentTimestamp + 120000,
|
|
||||||
value: Math.floor(Math.random() * 1000) + 1
|
|
||||||
}]);
|
|
||||||
|
|
||||||
// response = array of timestamps added by TS.MADD command.
|
|
||||||
if (response.length === 2) {
|
|
||||||
console.log('Added 2 entries to timeseries with TS.MADD.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update timeseries retention with TS.ALTER:
|
|
||||||
// https://oss.redis.com/redistimeseries/commands/#tsalter
|
|
||||||
const alterResponse = await client.ts.alter('mytimeseries', {
|
|
||||||
RETENTION: 0 // Keep the entries forever
|
|
||||||
});
|
|
||||||
|
|
||||||
if (alterResponse === 'OK') {
|
|
||||||
console.log('Timeseries retention settings altered successfully.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query the timeseries with TS.RANGE:
|
|
||||||
// https://oss.redis.com/redistimeseries/commands/#tsrangetsrevrange
|
|
||||||
const fromTimestamp = 1640995200000; // Jan 1 2022 00:00:00
|
|
||||||
const toTimestamp = 1640995260000; // Jan 1 2022 00:01:00
|
|
||||||
const rangeResponse = await client.ts.range('mytimeseries', fromTimestamp, toTimestamp, {
|
|
||||||
// Group into 10 second averages.
|
|
||||||
AGGREGATION: {
|
|
||||||
type: TimeSeriesAggregationType.AVERAGE,
|
|
||||||
timeBucket: 10000
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('RANGE RESPONSE:');
|
|
||||||
// rangeResponse looks like:
|
|
||||||
// [
|
|
||||||
// { timestamp: 1640995200000, value: 356.8 },
|
|
||||||
// { timestamp: 1640995210000, value: 534.8 },
|
|
||||||
// { timestamp: 1640995220000, value: 481.3 },
|
|
||||||
// { timestamp: 1640995230000, value: 437 },
|
|
||||||
// { timestamp: 1640995240000, value: 507.3 },
|
|
||||||
// { timestamp: 1640995250000, value: 581.2 },
|
|
||||||
// { timestamp: 1640995260000, value: 600 }
|
|
||||||
// ]
|
|
||||||
|
|
||||||
console.log(rangeResponse);
|
|
||||||
|
|
||||||
// Get some information about the state of the timeseries.
|
|
||||||
// https://oss.redis.com/redistimeseries/commands/#tsinfo
|
|
||||||
const tsInfo = await client.ts.info('mytimeseries');
|
|
||||||
|
|
||||||
// tsInfo looks like this:
|
|
||||||
// {
|
|
||||||
// totalSamples: 1440,
|
|
||||||
// memoryUsage: 28904,
|
|
||||||
// firstTimestamp: 1641508920000,
|
|
||||||
// lastTimestamp: 1641595320000,
|
|
||||||
// retentionTime: 86400000,
|
|
||||||
// chunkCount: 7,
|
|
||||||
// chunkSize: 4096,
|
|
||||||
// chunkType: 'uncompressed',
|
|
||||||
// duplicatePolicy: 'block',
|
|
||||||
// labels: [],
|
|
||||||
// sourceKey: null,
|
|
||||||
// rules: []
|
|
||||||
// }
|
|
||||||
|
|
||||||
console.log('Timeseries info:');
|
|
||||||
console.log(tsInfo);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.quit();
|
let value = Math.floor(Math.random() * 1000) + 1; // Random data point value
|
||||||
|
let currentTimestamp = 1640995200000; // Jan 1 2022 00:00:00
|
||||||
|
let num = 0;
|
||||||
|
|
||||||
|
while (num < 10000) {
|
||||||
|
// Add a new value to the timeseries, providing our own timestamp:
|
||||||
|
// https://redis.io/commands/ts.add/
|
||||||
|
await client.ts.add('mytimeseries', currentTimestamp, value);
|
||||||
|
console.log(`Added timestamp ${currentTimestamp}, value ${value}.`);
|
||||||
|
|
||||||
|
num += 1;
|
||||||
|
value = Math.floor(Math.random() * 1000) + 1; // Get another random value
|
||||||
|
currentTimestamp += 1000; // Move on one second.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add multiple values to the timeseries in round trip to the server:
|
||||||
|
// https://redis.io/commands/ts.madd/
|
||||||
|
const response = await client.ts.mAdd([{
|
||||||
|
key: 'mytimeseries',
|
||||||
|
timestamp: currentTimestamp + 60000,
|
||||||
|
value: Math.floor(Math.random() * 1000) + 1
|
||||||
|
}, {
|
||||||
|
key: 'mytimeseries',
|
||||||
|
timestamp: currentTimestamp + 120000,
|
||||||
|
value: Math.floor(Math.random() * 1000) + 1
|
||||||
|
}]);
|
||||||
|
|
||||||
|
// response = array of timestamps added by TS.MADD command.
|
||||||
|
if (response.length === 2) {
|
||||||
|
console.log('Added 2 entries to timeseries with TS.MADD.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update timeseries retention with TS.ALTER:
|
||||||
|
// https://redis.io/commands/ts.alter/
|
||||||
|
const alterResponse = await client.ts.alter('mytimeseries', {
|
||||||
|
RETENTION: 0 // Keep the entries forever
|
||||||
|
});
|
||||||
|
|
||||||
|
if (alterResponse === 'OK') {
|
||||||
|
console.log('Timeseries retention settings altered successfully.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query the timeseries with TS.RANGE:
|
||||||
|
// https://redis.io/commands/ts.range/
|
||||||
|
const fromTimestamp = 1640995200000; // Jan 1 2022 00:00:00
|
||||||
|
const toTimestamp = 1640995260000; // Jan 1 2022 00:01:00
|
||||||
|
const rangeResponse = await client.ts.range('mytimeseries', fromTimestamp, toTimestamp, {
|
||||||
|
// Group into 10 second averages.
|
||||||
|
AGGREGATION: {
|
||||||
|
type: TimeSeriesAggregationType.AVERAGE,
|
||||||
|
timeBucket: 10000
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('RANGE RESPONSE:');
|
||||||
|
// rangeResponse looks like:
|
||||||
|
// [
|
||||||
|
// { timestamp: 1640995200000, value: 356.8 },
|
||||||
|
// { timestamp: 1640995210000, value: 534.8 },
|
||||||
|
// { timestamp: 1640995220000, value: 481.3 },
|
||||||
|
// { timestamp: 1640995230000, value: 437 },
|
||||||
|
// { timestamp: 1640995240000, value: 507.3 },
|
||||||
|
// { timestamp: 1640995250000, value: 581.2 },
|
||||||
|
// { timestamp: 1640995260000, value: 600 }
|
||||||
|
// ]
|
||||||
|
|
||||||
|
console.log(rangeResponse);
|
||||||
|
|
||||||
|
// Get some information about the state of the timeseries.
|
||||||
|
// https://redis.io/commands/ts.info/
|
||||||
|
const tsInfo = await client.ts.info('mytimeseries');
|
||||||
|
|
||||||
|
// tsInfo looks like this:
|
||||||
|
// {
|
||||||
|
// totalSamples: 1440,
|
||||||
|
// memoryUsage: 28904,
|
||||||
|
// firstTimestamp: 1641508920000,
|
||||||
|
// lastTimestamp: 1641595320000,
|
||||||
|
// retentionTime: 86400000,
|
||||||
|
// chunkCount: 7,
|
||||||
|
// chunkSize: 4096,
|
||||||
|
// chunkType: 'uncompressed',
|
||||||
|
// duplicatePolicy: 'block',
|
||||||
|
// labels: [],
|
||||||
|
// sourceKey: null,
|
||||||
|
// rules: []
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log('Timeseries info:');
|
||||||
|
console.log(tsInfo);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeSeries();
|
await client.quit();
|
||||||
|
205
examples/topk.js
205
examples/topk.js
@@ -1,112 +1,113 @@
|
|||||||
// This example demonstrates the use of the Top K
|
// This example demonstrates the use of the Top K
|
||||||
// in the RedisBloom module (https://redisbloom.io/)
|
// in the RedisBloom module (https://redis.io/docs/stack/bloom/)
|
||||||
|
|
||||||
import { createClient } from 'redis';
|
import { createClient } from 'redis';
|
||||||
|
|
||||||
async function topK() {
|
const client = createClient();
|
||||||
const client = createClient();
|
|
||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
// Delete any pre-existing Top K.
|
// Delete any pre-existing Top K.
|
||||||
await client.del('mytopk');
|
await client.del('mytopk');
|
||||||
|
|
||||||
// Reserve a Top K to track the 10 most common items.
|
// Reserve a Top K to track the 10 most common items.
|
||||||
// https://oss.redis.com/redisbloom/TopK_Commands/#topkreserve
|
// https://redis.io/commands/topk.reserve/
|
||||||
try {
|
try {
|
||||||
await client.topK.reserve('mytopk', 10);
|
await client.topK.reserve('mytopk', 10, { width: 400, depth: 10, decay: 0.9 });
|
||||||
console.log('Reserved Top K.');
|
console.log('Reserved Top K.');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message.endsWith('key already exists')) {
|
if (e.message.endsWith('key already exists')) {
|
||||||
console.log('Top K already reserved.');
|
console.log('Top K already reserved.');
|
||||||
} else {
|
} else {
|
||||||
console.log('Error, maybe RedisBloom is not installed?:');
|
console.log('Error, maybe RedisBloom is not installed?:');
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const teamMembers = [
|
|
||||||
'leibale',
|
|
||||||
'simon',
|
|
||||||
'guy',
|
|
||||||
'suze',
|
|
||||||
'brian',
|
|
||||||
'steve',
|
|
||||||
'kyleb',
|
|
||||||
'kyleo',
|
|
||||||
'josefin',
|
|
||||||
'alex',
|
|
||||||
'nava',
|
|
||||||
'lance',
|
|
||||||
'rachel',
|
|
||||||
'kaitlyn'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Add random counts for random team members with TOPK.INCRBY
|
|
||||||
for (let n = 0; n < 1000; n++) {
|
|
||||||
const teamMember = teamMembers[Math.floor(Math.random() * teamMembers.length)];
|
|
||||||
const points = Math.floor(Math.random() * 1000) + 1;
|
|
||||||
await client.topK.incrBy('mytopk', {
|
|
||||||
item: teamMember,
|
|
||||||
incrementBy: points
|
|
||||||
});
|
|
||||||
console.log(`Added ${points} points for ${teamMember}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// List out the top 10 with TOPK.LIST
|
|
||||||
const top10 = await client.topK.list('mytopk');
|
|
||||||
console.log('The top 10:');
|
|
||||||
// top10 looks like this:
|
|
||||||
// [
|
|
||||||
// 'guy', 'nava',
|
|
||||||
// 'kaitlyn', 'brian',
|
|
||||||
// 'simon', 'suze',
|
|
||||||
// 'lance', 'alex',
|
|
||||||
// 'steve', 'kyleo'
|
|
||||||
// ]
|
|
||||||
console.log(top10);
|
|
||||||
|
|
||||||
// List out the top 10 with their counts (requires RedisBloom >=2.2.9)
|
|
||||||
const top10WithCounts = await client.topK.listWithCount('mytopk');
|
|
||||||
console.log('The top 10 with counts:');
|
|
||||||
console.log(top10WithCounts);
|
|
||||||
// top10WithCounts looks like this:
|
|
||||||
// [
|
|
||||||
// { item: 'suze', count: 42363 },
|
|
||||||
// { item: 'lance', count: 41982 },
|
|
||||||
// { item: 'simon', count: 41831 },
|
|
||||||
// { item: 'steve', count: 39237 },
|
|
||||||
// { item: 'guy', count: 39078 },
|
|
||||||
// { item: 'kyleb', count: 37338 },
|
|
||||||
// { item: 'leibale', count: 34230 },
|
|
||||||
// { item: 'kyleo', count: 33812 },
|
|
||||||
// { item: 'alex', count: 33679 },
|
|
||||||
// { item: 'nava', count: 32663 }
|
|
||||||
// ]
|
|
||||||
|
|
||||||
// Check if a few team members are in the top 10 with TOPK.QUERY:
|
|
||||||
const [ steve, suze, leibale, frederick ] = await client.topK.query('mytopk', [
|
|
||||||
'steve',
|
|
||||||
'suze',
|
|
||||||
'leibale',
|
|
||||||
'frederick'
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log(`steve ${steve === 1 ? 'is': 'is not'} in the top 10.`);
|
|
||||||
console.log(`suze ${suze === 1 ? 'is': 'is not'} in the top 10.`);
|
|
||||||
console.log(`leibale ${leibale === 1 ? 'is': 'is not'} in the top 10.`);
|
|
||||||
console.log(`frederick ${frederick === 1 ? 'is': 'is not'} in the top 10.`);
|
|
||||||
|
|
||||||
// Get count estimate for some team members:
|
|
||||||
const [ simonCount, lanceCount ] = await client.topK.count('mytopk', [
|
|
||||||
'simon',
|
|
||||||
'lance'
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log(`Count estimate for simon: ${simonCount}.`);
|
|
||||||
console.log(`Count estimate for lance: ${lanceCount}.`);
|
|
||||||
|
|
||||||
await client.quit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
topK();
|
const teamMembers = [
|
||||||
|
'leibale',
|
||||||
|
'simon',
|
||||||
|
'guy',
|
||||||
|
'suze',
|
||||||
|
'brian',
|
||||||
|
'steve',
|
||||||
|
'kyleb',
|
||||||
|
'kyleo',
|
||||||
|
'josefin',
|
||||||
|
'alex',
|
||||||
|
'nava',
|
||||||
|
'lance',
|
||||||
|
'rachel',
|
||||||
|
'kaitlyn'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Add random counts for random team members with TOPK.INCRBY
|
||||||
|
// https://redis.io/commands/topk.incrby/
|
||||||
|
for (let n = 0; n < 1000; n++) {
|
||||||
|
const teamMember = teamMembers[Math.floor(Math.random() * teamMembers.length)];
|
||||||
|
const points = Math.floor(Math.random() * 1000) + 1;
|
||||||
|
await client.topK.incrBy('mytopk', {
|
||||||
|
item: teamMember,
|
||||||
|
incrementBy: points
|
||||||
|
});
|
||||||
|
console.log(`Added ${points} points for ${teamMember}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List out the top 10 with TOPK.LIST
|
||||||
|
// https://redis.io/commands/topk.list/
|
||||||
|
const top10 = await client.topK.list('mytopk');
|
||||||
|
console.log('The top 10:');
|
||||||
|
// top10 looks like this:
|
||||||
|
// [
|
||||||
|
// 'guy', 'nava',
|
||||||
|
// 'kaitlyn', 'brian',
|
||||||
|
// 'simon', 'suze',
|
||||||
|
// 'lance', 'alex',
|
||||||
|
// 'steve', 'kyleo'
|
||||||
|
// ]
|
||||||
|
console.log(top10);
|
||||||
|
|
||||||
|
// List out the top 10 with their counts (requires RedisBloom >=2.2.9)
|
||||||
|
// https://redis.io/commands/topk.list/
|
||||||
|
const top10WithCounts = await client.topK.listWithCount('mytopk');
|
||||||
|
console.log('The top 10 with counts:');
|
||||||
|
console.log(top10WithCounts);
|
||||||
|
// top10WithCounts looks like this:
|
||||||
|
// [
|
||||||
|
// { item: 'suze', count: 42363 },
|
||||||
|
// { item: 'lance', count: 41982 },
|
||||||
|
// { item: 'simon', count: 41831 },
|
||||||
|
// { item: 'steve', count: 39237 },
|
||||||
|
// { item: 'guy', count: 39078 },
|
||||||
|
// { item: 'kyleb', count: 37338 },
|
||||||
|
// { item: 'leibale', count: 34230 },
|
||||||
|
// { item: 'kyleo', count: 33812 },
|
||||||
|
// { item: 'alex', count: 33679 },
|
||||||
|
// { item: 'nava', count: 32663 }
|
||||||
|
// ]
|
||||||
|
|
||||||
|
// Check if a few team members are in the top 10 with TOPK.QUERY:
|
||||||
|
// https://redis.io/commands/topk.query/
|
||||||
|
const [ steve, suze, leibale, frederick ] = await client.topK.query('mytopk', [
|
||||||
|
'steve',
|
||||||
|
'suze',
|
||||||
|
'leibale',
|
||||||
|
'frederick'
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(`steve ${steve === 1 ? 'is': 'is not'} in the top 10.`);
|
||||||
|
console.log(`suze ${suze === 1 ? 'is': 'is not'} in the top 10.`);
|
||||||
|
console.log(`leibale ${leibale === 1 ? 'is': 'is not'} in the top 10.`);
|
||||||
|
console.log(`frederick ${frederick === 1 ? 'is': 'is not'} in the top 10.`);
|
||||||
|
|
||||||
|
// Get count estimate for some team members with TOPK.COUNT:
|
||||||
|
// https://redis.io/commands/topk.count/
|
||||||
|
const [ simonCount, lanceCount ] = await client.topK.count('mytopk', [
|
||||||
|
'simon',
|
||||||
|
'lance'
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(`Count estimate for simon: ${simonCount}.`);
|
||||||
|
console.log(`Count estimate for lance: ${lanceCount}.`);
|
||||||
|
|
||||||
|
await client.quit();
|
||||||
|
Reference in New Issue
Block a user