Video
Learn more
Redis OM for Node.js is still in its early days, but we’re making a lot of progress. Here’s what we added in the latest version and where we’re headed.
I released a preview of Redis OM for Node.js a few months back. I was pretty happy with it at the time. It did the things it was supposed to do, at least this early in a development cycle.
One element that made me particularly happy was the fluent interface for searching. You know, this thing:
const albums = await repository.search()
.where('artist').equals('Mushroomhead')
.and('title').matches('butterfly')
.and('year').is.greaterThan(2000)
.return.all()
But the best part—the part I’ve been most happy with—is how much Redis OM for Node.js has been embraced and used by the developer community. Many of you have given me a lot of useful and actionable feedback, often via our Discord server. Plus, you fixed bugs and even sent in complete features from my rather sparsely defined issues on GitHub. Your assistance is truly appreciated.
I’ve incorporated your feedback and your pull requests, and your contributions. In this post, I summarize some of the changes that we—and by “we” I mean “you and I”—have made to Redis OM.
Early on, some rando on the Internet suggested that calls to .createEntity should take initial values for that Entity. I thought this was a great idea and adopted it in Redis OM.
So what was once a bit verbose:
const album = albumRepository.createEntity()
album.artist = "Mushroomhead"
album.title = "The Righteous & The Butterfly"
album.year = 2014
album.genres = [ 'metal' ]
album.outOfPublication = true
const id = await albumRepository.save(album)
Became much tidier:
const album = albumRepository.createEntity({
artist: "Mushroomhead",
title: "The Righteous & The Butterfly",
year: 2014,
genres: [ 'metal' ],
outOfPublication: true
})
const id = await albumRepository.save(album)
I even added a .createAndSave method to eliminate the call to .save because this is such a common pattern:
const album = await albumRepository.createAndSave({
artist: "Mushroomhead",
title: "The Righteous & The Butterfly",
year: 2014,
genres: [ 'metal' ],
outOfPublication: true
})
Thanks for the suggestion. It was a solid one.
Redis makes an awesome database but also a pretty good cache. Many of you suggested we needed a way to create expiring Entities.
Ask and ye shall receive:
const ttlInSeconds = 12 * 60 * 60 // 12 hours
await albumRepository.expire('01FVDN241NGTPHSAV0DFDBXC90', ttlInSeconds)
Not sure why you’d want to expire a Mushroomhead album, but de gustibus non est disputandum.
Nobody asked for these, but I wanted them anyhow! RediSearch has good support for location with the GEO type, and dates are used in all sorts of applications. So I added them as point and date, respectively.:
const studioSchema = new Studio(Studio, {
name: { type: 'string' },
city: { type: 'string' },
state: { type: 'string' },
location: { type: 'point' },
established: { type: 'date' }
})
And, of course, they’re perfectly usable with the fluent search interface:
const studios = await studioRepository.search()
.where('established').after(date)
.return.all()
const studios = await studioRepository.search()
.where('location').inRadius(
circle => circle.origin(-81.7758995, 41.4976393).radius(50).miles)
.return.all()
Probably my favorite change in Redis OM for Node.js is how it works with Node Redis. In the preview, you could .open a client that used Node Redis behind the scenes:
const client = new Client()
await client.open('redis://localhost:6379')
Now, you can .use an existing connection from Node Redis:
import { createClient } from 'redis'
const redis = createClient('redis://localhost:6379')
await redis.connect()
const client = await new Client().use(redis)
This lets you connect to Redis in all sorts of ways, not just with a simple connection string. I also changed .open and .use to return the Client to allow nifty one-liners:
const client = await new Client().open('redis://localhost:6379')
No preview is perfect; that’s why it’s a preview. I learned a lot by watching people’s mistakes while using Redis OM for Node.js. Mistakes that were the result of misunderstanding parts of the interface to Redis OM. Parts that need improvement because I had not sufficiently thought them through. These improvements resulted in a few important but breaking changes.
I noticed a lot of folks being confused when they were using a string as a TEXT versus a TAG in RediSearch. So I made this distinction explicit by breaking the string type into two types: string and text.
I also learned that it was unclear that the array type could only be an array of strings. I changed it to string[]:
let albumSchema = new Schema(Album, {
artist: { type: 'string' },
title: { type: 'text' },
year: { type: 'number' },
genres: { type: 'string[]' },
outOfPublication: { type: 'boolean' }
})
Almost everyone using Redis OM was using RediSearch and RedisJSON. They were choosing to store their documents as JSON documents. But in the preview, Redis OM used Hashes as the default storage mechanism.
This resulted in everyone having to tell Redis OM to use JSON explicitly:
let albumSchema = new Schema(Album, {
artist: { type: 'string' },
title: { type: 'string' },
year: { type: 'number' },
genres: { type: 'string[]' },
outOfPublication: { type: 'boolean' }
}, {
dataStructure: 'JSON'
})
To avoid this step, I changed the default:
let albumSchema = new Schema(Album, {
artist: { type: 'string' },
title: { type: 'string' },
year: { type: 'number' },
genres: { type: 'string[]' },
outOfPublication: { type: 'boolean' }
})
This change really didn’t impact all that many developers as you were all using JSON anyhow. But it is nice to know that you can now delete just a little more code!
Of course, software is never complete. I have more things I want to add to Redis OM than I probably have time to implement. Here’s a few of the things that I’m looking at for future releases:
I’ve also been working on some helpful content if you’re getting started with Redis OM:
So how’s that for a summary of what’s new with Redis OM for Node.js? Redis OM is what it is because of the assistance from folks in the community. So, I’d like to close with a hearty “Thank you” to some of the helpful folks who have… well… helped:
I’m sure I’ve missed some of you, but know that GitHub’s commit history will never forget.