Redis as a Database with Redis OM
Tags: redis, database, graphql, aspnet
Published: 2022-11-13 15:53:57

---
title: Redis as a Database with Redis OM
published: true
description: 
tags: redis, database, graphql, aspnet
series: Redis as a Database
cover_image: https://cdn-images-1.medium.com/max/7718/1*Aq_K9xeBLdf9ZdXrDC4XVw.jpeg
# Use a ratio of 100:42 for best results.
# published_at: 2022-11-13 15:46 +0000
---

My newest interest is [Redis](https://redis.io/), an in-memory data store for key-value pairs, streaming, message brokering and a database.

In this post I’ll give you an introduction into using Redis as a normal database. The code snippets will use C# and the final result will look very familiar to anyone who used Entity Framework.

What you’re not getting is a spoon-feeding, instead you’re going to see the relevant parts of Visualizer, a [pet project of mine](https://github.com/mariusmuntean/Visualizer), where I’m using Redis to ingest and query tweets from Twitter’s [sample steam](https://developer.twitter.com/en/docs/twitter-api/tweets/volume-streams/api-reference/get-tweets-sample-stream).

## Tools

Setting up all the tools is beyond the scope of this post, but I still want to mention the most essential things.

[Redis Stack](https://redis.com/blog/introducing-redis-stack/): a suite of multiple components, that includes a Redis instance, multiple Redis modules and RedisInsight. Two modules, RediSearch and RedisJSON are essential here, as they allow us to use Redis as a proper DB. The simplest way to get going is to use the [official Docker container](https://redis.io/docs/stack/get-started/install/docker/).

[Redis OM .NET](https://github.com/redis/redis-om-dotnet): an official .NET library that offers (CLR) object mapping and query translation. I can recommend it wholeheartedly, even though it isn’t perfect. The excellent community and maintainers go above and beyond the call of duty. Ask them anything on the [official Discord server](http://discord.gg/redis).

A good .NET IDE: like VS Code, Visual Studio Proper or Rider.

And finally, a few spare minutes.

## Data Modeling

In Visualizer, I’m receiving a stream of tweets, including their many properties and nested data, which represent 1% of the “real-time” tweets.

The fields are described in the official [Twitter API documentation](https://developer.twitter.com/en/docs/twitter-api/tweets/volume-streams/api-reference/get-tweets-sample-stream), look for *Response Fields*.

To store and retrieve the data, I’m using Redis OM, which wants a normal C# class whose properties are annotated.

The data model for a single tweet looks like this
{% gist https://gist.github.com/mariusmuntean/7526cec1df777c9e50c7faca1e048d79.js %}
You can find the full file [here](https://github.com/mariusmuntean/Visualizer/tree/a76d42973ed55a358af06f71fc786be1b3a8a88e/Visualizer.Shared.Models).

Notice that the class is annotated as a *Document *with *StorageType* JSON. This lets Redis OM know that we want to store instances of this class in a searchable way and in JSON format. The *Prefixes* is just for our convenience, to make it easier to distinguish the data in Redis, in case that we have multiple document types.

Each property is also annotated, to instruct Redis OM (and indirectly RediSearch and RedisJSON) which fields should be searchable and how exactly.

* The attribute *RedisIdField* is manadatory and you can interpret it as the primary key of a tweet.

* *Indexed* does exactly what you’d expect.

* *Searchable* is powerful, because it allows full text search in the string property.

*CascadeDepth* tells Redis OM how deep it should look for annotated properties. My *TweetModel* class has an array of *ReferencedTweet* instance. The *ReferencedTweet* class is not marked as a *Document* because it is nested inside the *TweetModel*. It will however contain its own annotated properties. That’s why I set the depth to 1.

All attributes are described [here](https://github.com/redis/redis-om-dotnet#-modeling-your-domain-and-indexing-it).

## Create the Index

After the data is modelled, a so-called *index* needs to be created in Redis.

First, create a *RedisConnectionProvider*. In my Visualizer project I’m adding one to the DI container with an extension method
{% gist https://gist.github.com/mariusmuntean/b379248abcecba41a6d8be0414f817f1.js %}
Then, let Redis OM send the command that instructs RediSearch/RedisJSON which field is searchable and how. I’m doing it when one of my microservices starts up.
{% gist https://gist.github.com/mariusmuntean/55a48b89f75563f579d11b6ac5c23a98.js %}
In Redis, the index will have the name *tweetmodel-idx*. You can list them all by issuing *FT._LIST* in the Redis CLI or get a detailed explanation of an index with *FT.INFO tweetmodel-idx***.**

## Data Storing

After you have a few tweets (I’m using a library called [Tweetinvi](https://github.com/linvi/tweetinvi)) you want to store them.

Redis OM makes this easy by offering us a *RedisCollection<T>*, where *T* is our data model, e.g. *TweetModel*. If it helps, this is analogous to a *DbSet<T>* in Entity Framework,

To get a hold of such a collection, you make use of the *RedisConnectionProvider* that you registered previously
{% gist https://gist.github.com/mariusmuntean/463de4bf27dbb61d6b6b3f5691a33f8f.js %}
On it you call *InsertAsync() *and provide your *TweetModel* instance
{% gist https://gist.github.com/mariusmuntean/5456fe6f1b82f9146a24a856f21a6858.js %}
That’s it, your tweet is now stored in Redis. You can now have a look at your data with RedisInsight. This is how it looks for me

![Stored Tweets in RedisInsight](https://cdn-images-1.medium.com/max/5840/1*3ZZFUt0z5zAYk4ltf0RxJA.png)

## Filter, Sort and Paginate Tweets

I usually work with relational DBs (mostly Postgres), where filtering, sorting and paginating results is as common as it gets.

In Redis, especially using Redis OM, this is as easy as we’re used to as Entity Framework users.

First, we need a DTO that defines all the necessary filtering, sorting and pagination fields.
{% gist https://gist.github.com/mariusmuntean/5938ac638078e4483528c70081b98696.js %}
Visualizer offers a GraphQL API, hence the “Input” in the DTOs name.

Next, we have to formulate a query based on the DTO and retrieve the tweets that match that query.

First, get a new *RedisCollection* instance like you saw in the previous section
{% gist https://gist.github.com/mariusmuntean/463de4bf27dbb61d6b6b3f5691a33f8f.js %}
Then you can start filtering, e.g. by a tweet’s ID
{% gist https://gist.github.com/mariusmuntean/64f270211c95d4a4b666f66cdb5f8c04.js %}
Remember that *TweetModel.Text* was annotated as *Searchable*, which allows for full text searches. To filter only tweets that contain a certain word in their text you’d write something like this
{% gist https://gist.github.com/mariusmuntean/3686a86d3d584be7f179c3a0fc22623a.js %}
Note that there’s no call to *Contains()* or anything like that, just a simple *==*.

The *TweetModel.CreatedAt* property is *Indexed* and *Searchable*
{% gist https://gist.github.com/mariusmuntean/4b14756f98338a7d9ecaaa8fccc77df4.js %}
Tweets can be filtered by date like so
{% gist https://gist.github.com/mariusmuntean/c58deb92e59037d1a25c38f603f08ae4.js %}
A cool feature of Redis is its native support for the geolocation data type. Tweets can include geolocation information and to filter the tweets that are at a certain distance from a location you’d write something like this
{% gist https://gist.github.com/mariusmuntean/100cdafaff1ac63918c2b601095e373f.js %}
Sorting and pagination are nothing special
{% gist https://gist.github.com/mariusmuntean/3c55704a1b3ebdfa91641a8f32c6ba78.js %}
Finally, you’d want to materialize the query and get your tweets
{% gist https://gist.github.com/mariusmuntean/c6c99231089ffc842aa400f33ee05ac2.js %}
Visualizer has a simple React frontend that allows to query for tweets

![Filter, sort and paginate tweets](https://cdn-images-1.medium.com/max/7360/1*o6n1Mh9PvdyN8HWadFNIqQ.png)

And even to filter them by location

![Filter by location and show on map](https://cdn-images-1.medium.com/max/7360/1*UbQRXHqlfXGXLSAzAnzR9w.png)


## There's More to Come

I’m planning to write a few more posts about Visualizer, where I show Redis’ PubSub, quick ranking with SortedSets and GraphQL subscriptions.

If you liked this post let me know on Twitter 😉 (@MunteanMarius), give it a ❤️ and follow me to get more content on Redis, Azure, MAUI and other cool stuff.

## Other content on this topic

[Hussein Nasser — Can Redis be used as a Primary database?](https://www.youtube.com/watch?v=VLTPqImLapM)

[Redis — Redis as a Primary Database](https://www.youtube.com/watch?v=SGEG5q4LT9s)

[DevTalk 83: The hidden features of Redis. With Marius Muntean](https://kerry.lothrop.de/devtalk-83-marius-muntean/)