Object mapping, and more, for Redis and Node.js. Written in TypeScript.
Object mapping, and more, for Redis and Node.js. Written in TypeScript.
Object mapping, and more, for Redis and Node.js. Written in TypeScript.
[![Discord][discord-shield]][discord-url] [![Twitch][twitch-shield]][twitch-url] [![YouTube][youtube-shield]][youtube-url] [![Twitter][twitter-shield]][twitter-url]
[![NPM][package-shield]][package-url] [![Build][build-shield]][build-url] [![License][license-shield]][license-url]
Redis OM for Node.js makes it easy to model Redis data in your Node.js applications.
[Redis OM .NET][redis-om-dotnet] | Redis OM Node.js | [Redis OM Python][redis-om-python] | [Redis OM Spring][redis-om-spring]
Table of contents
Redis OM (pronounced REDiss OHM) makes it easy to add Redis to your Node.js application by mapping the Redis data structures you know and love to simple JavaScript objects. No more pesky, low-level commands, just pure code with a fluent interface.
Define a schema:
const schema = new Schema('album', {
artist: { type: 'string' },
title: { type: 'text' },
year: { type: 'number' }
})Create a JavaScript object and save it:
const album = {
artist: "Mushroomhead",
title: "The Righteous & The Butterfly",
year: 2014
}
await repository.save(album)Search for matching entities:
const albums = await repository.search()
.where('artist').equals('Mushroomhead')
.and('title').matches('butterfly')
.and('year').is.greaterThan(2000)
.return.all()Pretty cool, right? Read on for details.
⚠️ Warning: This Version Has Breaking Changes from 0.3.6
Redis OM 0.4 is new, improved, and includes breaking changes. If you're trying it for the first time, no worries. Just follow what's in this README and you'll be fine.
However, you might be a user of Redis OM already. If that is the case, you'll want to review this document to understand those changes.
Of course, you don't have to upgrade. If this is you, you'll want to check out the README for that version over on NPM.
However, I hope you choose to try the new version. It has many changes that have been frequently requested that are documented in the CHANGELOG. And more, non-breaking changes will follow these.
First things first, get yourself a Node.js project. There are lots of ways to do this, but I'm gonna go with a classic:
$ npm initOnce you have that sweet, sweet package.json, let's add our newest favorite package to it:
$ npm install redis-omRedis OM for Node.js uses Node Redis. So you should install that too:
$ npm install redisAnd, of course, you'll need some Redis, preferably [Redis Stack][redis-stack-url] as it comes with [RediSearch][redisearch-url] and [RedisJSON][redis-json-url] ready to go. The easiest way to do this is to set up a free [Redis Cloud][redis-cloud-url] instance. But, you can also use Docker:
$ docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latestExcellent. Setup done. Let's write some code!
Before you can use Redis OM, you need to connect to Redis with Node Redis. Here's how you do that, stolen straight from the top of the Node Redis README:
import { createClient } from 'redis'
const redis = createClient()
redis.on('error', (err) => console.log('Redis Client Error', err));
await redis.connect()Node Redis is a powerful piece of software with lots and lots of capabilities. Its details are way beyond the scope of this README. But, if you're curious—or if you need that power—you can find all the info in the Node Redis documentation.
Regardless, once you have a connection to Redis you can use it to execute Redis commands:
const aString = await redis.ping() // 'PONG'
const aNumber = await redis.hSet('foo', 'alfa', '42', 'bravo', '23') // 2
const aHash = await redis.hGetAll('foo') // { alfa: '42', bravo: '23' }You might not need to do this, but it's always handy to have the option. When you're done with a Redis connection, you can let the server know by calling .quit:
await redis.quit()By default, Node Redis connects to localhost on port 6379. This is, of course, configurable. Just pass in a url with the hostname and port that you want to use:
const redis = createClient({ url: 'redis://alice:[email protected]:6380' })The basic format for this URL is:
redis://username:password@host:portThis will probably cover most scenarios, but if you want something more, the full specification for the URL is defined with the IANA. And yes, there is a TLS version as well.
Node Redis has lots of other ways you can create a connection. You can use discrete parameters, UNIX sockets, and all sorts of cool things. Details can be found in the client configuration guide for Node Redis and the clusterting guide.
Redis OM is all about saving, reading, and deleting entities. An Entity is just data in a JavaScript object that you want to save or retrieve from Redis. Almost any JavaScript object is a valid Entity.
Schemas define fields that might be on an Entity. It includes a field's type, how it is stored internally in Redis, and how to search on it if you are using RediSearch. By default, they are mapped to JSON documents using RedisJSON, but you can change it to use Hashes if want (more on that later).
Ok. Let's start doing some object mapping and create a Schema:
import { Schema } from 'redis-om'
const albumSchema = new Schema('album', {
artist: { type: 'string' },
title: { type: 'text' },
year: { type: 'number' },
genres: { type: 'string[]' },
songDurations: { type: 'number[]' },
outOfPublication: { type: 'boolean' }
})
const studioSchema = new Schema('studio', {
name: { type: 'string' },
city: { type: 'string' },
state: { type: 'string' },
location: { type: 'point' },
established: { type: 'date' }
})The first argument is the Schema name. It defines the key name prefix that entities stored in Redis will have. It should be unique for your particular instance of Redis and probably meaningful to what you're doing. Here we have selected album for our album data and studio for data on recording studios. Imaginative, I know.
The second argument defines fields that might be stored in that key. The property name is the name of the field that you'll be referencing in your Redis OM queries. The type property tells Redis OM what sort of data is in that field. Valid types are: string, number, boolean, string[], number[], date, point, and text.
The first three types do exactly what you think—they define a field that is a String, a Number, or a Boolean. string[] and number[] do what you'd think as well, specifically describing an Array of Strings or Numbers respectively.
date is a little different, but still more or less what you'd expect. It describes a property that contains a Date and can be set using not only a Date but also a String containing an ISO 8601 date or a number with the UNIX epoch time in seconds (NOTE: the JavaScript Date object is specified in milliseconds).
A point defines a point somewhere on the globe as a longitude and a latitude. It is expressed as a simple object with longitude and latitude properties. Like this:
const point = { longitude: 12.34, latitude: 56.78 }A text field is a lot like a string. If you're just reading and writing objects, they are identical. But if you want to search on them, they are very, very different. I'll cover that in detail when I talk about searching but the tl;dr is that string fields can only be matched on their exact value and are best for keys and discrete data—like postal codes or status indicators—while text fields have full-text search enabled on them, are optimized for human-readable text, and can take advantage of stemming and stop words.
As I mentioned earlier, by default Redis OM stores your entities in JSON documents using RedisJSON. You can make this explicit in code if you like:
const albumSchema = new Schema('album', {
artist: { type: 'string' },
title: { type: 'string' },
year: { type: 'number' },
genres: { type: 'string[]' },
songDurations: { type: 'number[]' },
outOfPublication: { type: 'boolean' }
}, {
dataStructure: 'JSON'
})But you can also store your entities as Hashes instead. Just change the dataStructure property to reflect it:
const albumSchema = new Schema('album', {
artist: { type: 'string' },
title: { type: 'string' },
year: { type: 'number' },
genres: { type: 'string[]' },
outOfPublication: { type: 'boolean' }
}, {
dataStructure: 'HASH'
})And that's it.
Of course, Hashes and JSON are somewhat different data structures. Hashes are flat with fields containing values. JSON documents, however
No open issues yet, or sync has not completed.