@kirick/redis-store v0.1.0-beta.2
redis-store
Store you data in Redis and get it using indexes.
That package designed to help you to build a database using Redis' commands and some simple Lua scripts. You can store documents similar to MongoDB, you can find them, order and perform simple aggregations. It can be used, for example, to store and query some logs.
Redis server will know nothing about your database: schema of your database is only described at redis client.
All operations are designed to be atomic, so RedisStore guarantees that no operation will intercept another operation.
Installation
Run npm install @kirick/redis-client @kirick/redis-store oh-my-props
to install RedisClient, RedisStore and OhMyProps.
What can you do?
// First of all, import packages
import { createClient } from '@kirick/redis-client';
import RedisStore from '@kirick/redis-store';
import OhMyProps from 'oh-my-props';
// create connection to Redis
const redisClient = createClient({ url: 'redis://localhost' });
// and describe your database
// imagine a database of some users
const redisStore = new RedisStore(
redisClient,
{
// name of your database
namespace: 'users',
// list of indexes
index: [
{
field: 'user_id',
type: RedisStore.INDEX.UNIQUE, // unique index: you will not able to insert more than one document with the same value
},
{
field: 'user_name',
type: RedisStore.INDEX.HASH, // hash index: you will able to find documents with specific value
},
{
field: 'balance',
type: RedisStore.INDEX.RANGE, // range index: you will able to find documents between specific values
},
// you can insert documents with any other properties you want
// but you will not able to search over that fields
],
// remember that all properties will be converted to strings by Redis
// so you can use OhMyProps to convert documents coming from Redis
document_schema: new OhMyProps({
user_id: {
type: Number,
type_cast: true,
validator: (value) => Number.isInteger(value) && value >= 0,
},
user_name: {
type: String,
},
ts_created: {
type: Number,
type_cast: true,
validator: (value) => Number.isInteger(value) && value >= 0,
},
}),
},
);
Add documents
// you can insert one document
await redisStore.insertOne({
user_id : 1,
user_name: 'heavydog',
balance : 10,
});
// or you can insert array of documents at once
await redisStore.insertMany([
{
user_id : 2,
user_name: 'redelephant',
balance : 23,
},
{
user_id : 3,
user_name: 'sadmeercat',
balance : 53,
},
{
user_id : 4,
user_name: 'happycat',
balance : 12,
},
]);
You can add special property _ttl
to document to limit lifetime of that document in seconds. By now, RedisStore does not guarantee that you will never get expired documents from RedisStore in order to achieve high performance.
Find documents
You can find documents using method .find()
. It accepts an object with properties filter
, order
, offset
and count
.
Filter
Describe properties' values to find documents. Multiple properties will be combined using AND logical operation.
//
await redisStore.find({
filter: {
user_id: 1,
},
});
// -> [{ user_id: 1, user_name: 'heavydog', balance: 10 }]
// SQL equivalent: WHERE user_id = 1 AND balance = 123
await redisStore.find({
filter: {
user_id: 1,
balance: 123,
},
});
// -> []
You can use $in
to query by many values at once. $in
is available only on UNIQUE
and HASH
indexes.
// SQL equivalent: WHERE user_id IN (1, 4, 10)
await redisStore.find({
user_id: {
$in: [ 1, 4, 10 ],
},
});
// -> [{ user_id: 1, user_name: 'heavydog', balance: 10 },
// { user_id: 4, user_name: 'happycat', balance: 12 }]
To find documents by RANGE
index, use $gt
, $gte
, $lt
and $lte
.
// let's find users with balance from 12 (inclusive) to 53 (exclusive)
await redisStore.find({
balance: {
$gte: 12,
$lt : 53,
},
});
// -> [{ user_id: 3, user_name: 'sadmeercat', balance: 53 },
// { user_id: 4, user_name: 'happycat' , balance: 12 }]
By now you can not build complex filters using and
/ or
/ not
or other logical operations.
By now you can not find documents by non-indexed fields.
Order
It's easy to order documents by field with RANGE
index:
// let's find all document ordered by date of registration from newest ones:
await redisStore.find({
order: {
balance: -1, // set 1 to order ascending, -1 for descending
},
});
// -> [{ user_id: 3, user_name: 'sadmeercat' , balance: 53 },
// { user_id: 2, user_name: 'redelephant', balance: 23 },
// { user_id: 4, user_name: 'happycat' , balance: 12 },
// { user_id: 1, user_name: 'heavydog' , balance: 10 }]
By now you can not order documents by more than one field.
Offset and count
You can limit the range of documents you want to get:
// let's find all document but ordered by date of registration from newest ones:
await redisStore.find({
order: {
balance: -1,
},
offset: 1, // skip 1 document
count : 2, // get 2 documents
});
// -> [{ user_id: 2, user_name: 'redelephant', balance: 23 },
// { user_id: 4, user_name: 'happycat' , balance: 12 }]
Note: by default, count
is equal to 1000. Set it to -1
to get all matching documents.
Count documents
Use .count()
method to get count of matching documents. This method accepts filter
object itself.
// let's count all documents:
await redisStore.count();
// -> 4
// let's find count of users with balance greater than 15:
await redisStore.count({
balance: {
$gt: 15,
},
});
// -> 2
Delete documents
To delete documents you should find them using properties of .find()
method.
await redisStore.delete({
filter: {
user_id: {
$in: [ 1, 4, 10 ],
},
},
});
Note: by default, count
is equal to 1. Set it to -1
to delete all matching documents.
Aggregation
RedisStore offers simple aggregation functions.
Maximum
await redisStore.max(
// field name
'balance',
// `filter` object similar to `.find()` method
{}, // finding all documents
);
// -> 53
Note: you can call that method over field that doesn't have RANGE
index.
Minimum
await redisStore.min(
// field name
'balance',
// `filter` object similar to `.find()` method
{}, // finding all documents
);
// -> 10
Note: you can call that method over field that doesn't have RANGE
index.
Average
await redisStore.avg(
// field name
'balance',
// `filter` object similar to `.find()` method
{}, // finding all documents
);
// -> 24.5
Note: that method does not work with indexes.
Percentile
await redisStore.percentile(
// field name
'balance',
// threshold (value between 0 and 1)
0.25, // will find 25-percentile
// `filter` object similar to `.find()` method
{}, // finding all documents
);
// -> 12
Note: you can not call that method over field that doesn't have RANGE
index.
2 years ago
2 years ago