• Stars
    star
    457
  • Rank 95,775 (Top 2 %)
  • Language
    C#
  • License
    MIT License
  • Created about 3 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Object mapping, and more, for Redis and .NET


Redis OM

Object mapping, and more, for Redis and .NET


NuGet License Build Status

Redis OM .NET makes it easy to model Redis data in your .NET Applications.

Redis OM .NET | Redis OM Node.js | Redis OM Spring | Redis OM Python

Table of contents

πŸ’‘ Why Redis OM?

Redis OM provides high-level abstractions for using Redis in .NET, making it easy to model and query your Redis domain objects.

This preview release contains the following features:

  • Declarative object mapping for Redis objects
  • Declarative secondary-index generation
  • Fluent APIs for querying Redis
  • Fluent APIs for performing Redis aggregations

πŸ’» Installation

Using the dotnet cli, run:

dotnet add package Redis.OM

🏁 Getting started

Starting Redis

Before writing any code you'll need a Redis instance with the appropriate Redis modules! The quickest way to get this is with Docker:

docker run -p 6379:6379 -p 8001:8001 redis/redis-stack

This launches the redis-stack an extension of Redis that adds all manner of modern data structures to Redis. You'll also notice that if you open up http://localhost:8001 you'll have access to the redis-insight GUI, a GUI you can use to visualize and work with your data in Redis.

πŸ“‡ Modeling your domain (and indexing it!)

With Redis OM, you can model your data and declare indexes with minimal code. For example, here's how we might model a customer object:

[Document(StorageType = StorageType.Json)]
public class Customer
{
   [Indexed] public string FirstName { get; set; }
   [Indexed] public string LastName { get; set; }
   public string Email { get; set; }
   [Indexed(Sortable = true)] public int Age { get; set; }
   [Indexed] public string[] NickNames {get; set;}
}

Notice that we've applied the Document attribute to this class. We've also specified that certain fields should be Indexed.

Now we need to create the Redis index. So we'll connect to Redis and then call CreateIndex on an IRedisConnection:

var provider = new RedisConnectionProvider("redis://localhost:6379");
provider.Connection.CreateIndex(typeof(Customer));

Indexing Embedded Documents

There are two methods for indexing embedded documents with Redis.OM, an embedded document is a complex object, e.g. if our Customer model had an Address property with the following model:

[Document(IndexName = "address-idx", StorageType = StorageType.Json)]
public partial class Address
{
    public string StreetName { get; set; }
    public string ZipCode { get; set; }
    [Indexed] public string City { get; set; }
    [Indexed] public string State { get; set; }
    [Indexed(CascadeDepth = 1)] public Address ForwardingAddress { get; set; }
    [Indexed] public GeoLoc Location { get; set; }
    [Indexed] public int HouseNumber { get; set; }
}

Index By JSON Path

You can index fields by JSON path, in the top level model, in this case Customer you can decorate the Address property with an Indexed and/or Searchable attribute, specifying the JSON path to the desired field:

[Document(StorageType = StorageType.Json)]
public class Customer
{
   [Indexed] public string FirstName { get; set; }
   [Indexed] public string LastName { get; set; }
   public string Email { get; set; }
   [Indexed(Sortable = true)] public int Age { get; set; }
   [Indexed] public string[] NickNames {get; set;}
   [Indexed(JsonPath = "$.ZipCode")]
   [Searchable(JsonPath = "$.StreetAddress")]
   public Address Address {get; set;}
}
Indexing Arrays of Objects

This methodology can also be used for indexing string and string-like value-types within objects within Arrays and Lists, so for example if we had an array of Addresses, and we wanted to index the cities within those addresses we could do so with the following

[Indexed(JsonPath = "$.City")]
public Address[] Addresses { get; set; }

Those Cities can then be queried with an Any predicate within the main Where clause.

collection.Where(c=>c.Addresses.Any(a=>a.City == "Satellite Beach"))

Cascading Index

Alternatively, you can also embedded models by cascading indexes. In this instance you'd simply decorate the property with Indexed and set the CascadeDepth to whatever to however may levels you want the model to cascade for. The default is 0, so if CascadeDepth is not set, indexing an object will be a no-op:

[Document(StorageType = StorageType.Json)]
public class Customer
{
   [Indexed] public string FirstName { get; set; }
   [Indexed] public string LastName { get; set; }
   public string Email { get; set; }
   [Indexed(Sortable = true)] public int Age { get; set; }
   [Indexed] public string[] NickNames {get; set;}
   [Indexed(CascadeDepth = 2)]
   public Address Address {get; set;}
}

In the above case, all indexed/searchable fields in Address will be indexed down 2 levels, so the ForwardingAddress field in Address will also be indexed.

Once the index is created, we can:

  • Insert Customer objects into Redis
  • Get a Customer object by ID from Redis
  • Query Customers from Redis
  • Run aggregations on Customers in Redis

Let's see how!

Indexing DateTimes

As of version 0.4.0, all DateTime objects are indexed as numerics, and they are inserted as numerics into JSON documents. Because of this, you can query them as if they were numerics!

πŸ”‘ Keys and Ids

ULIDs and strings

Ids are unique per object, and are used as part of key generation for the primary index in Redis. The natively supported Id type in Redis OM is the ULID. You can bind ids to your model, by explicitly decorating your Id field with the RedisIdField attribute:

[Document(StorageType = StorageType.Json)]
public class Customer
{
    [RedisIdField] public Ulid Id { get; set; }
    [Indexed] public string FirstName { get; set; }
    [Indexed] public string LastName { get; set; }
    public string Email { get; set; }
    [Indexed(Sortable = true)] public int Age { get; set; }
    [Indexed] public string[] NickNames { get; set; }
}

When you call Set on the RedisConnection or call Insert in the RedisCollection, to insert your object into Redis, Redis OM will automatically set the id for you and you will be able to access it in the object. If the Id type is a string, and there is no explicitly overriding IdGenerationStrategy on the object, the ULID for the object will bind to the string.

Other types of ids

Redis OM also supports other types of ids, ids must either be strings or value types (e.g. ints, longs, GUIDs etc. . .), if you want a non-ULID id type, you must either set the id on each object prior to insertion, or you must register an IIdGenerationStrategy with the DocumentAttribute class.

Register IIdGenerationStrategy

To Register an IIdGenerationStrategy with the DocumentAttribute class, simply call DocumentAttribute.RegisterIdGenerationStrategy passing in the strategy name, and the implementation of IIdGenerationStrategy you want to use. Let's say for example you had the StaticIncrementStrategy, which maintains a static counter in memory, and increments ids based off that counter:

public class StaticIncrementStrategy : IIdGenerationStrategy
{
    public static int Current = 0;
    public string GenerateId()
    {
        return (Current++).ToString();
    }
}

You would then register that strategy with Redis.OM like so:

DocumentAttribute.RegisterIdGenerationStrategy(nameof(StaticIncrementStrategy), new StaticIncrementStrategy());

Then, when you want to use that strategy for generating the Ids of a document, you can simply set the IdGenerationStrategy of your document attribute to the name of the strategy.

[Document(IdGenerationStrategyName = nameof(StaticIncrementStrategy))]
public class ObjectWithCustomIdGenerationStrategy
{
    [RedisIdField] public string Id { get; set; }
}

Key Names

The key names are, by default, the fully qualified class name of the object, followed by a colon, followed by the Id. For example, there is a Person class in the Unit Test project, an example id of that person class would be Redis.OM.Unit.Tests.RediSearchTests.Person:01FTHAF0D1EKSN0XG67HYG36GZ, because Redis.OM.Unit.Tests.RediSearchTests.Person is the fully qualified class name, and 01FTHAF0D1EKSN0XG67HYG36GZ is the ULID (the default id type). If you want to change the prefix (the fully qualified class name), you can change that in the DocumentAttribute by setting the Prefixes property, which is an array of strings e.g.

[Document(Prefixes = new []{"Person"})]
public class Person

Note: At this time, Redis.OM will only use the first prefix in the prefix list as the prefix when creating a key name. However, when an index is created, it will be created on all prefixes enumerated in the Prefixes property

πŸ”Ž Querying

We can query our domain using expressions in LINQ, like so:

var customers = provider.RedisCollection<Customer>();

// Insert customer
customers.Insert(new Customer()
{
    FirstName = "James",
    LastName = "Bond",
    Age = 68,
    Email = "[email protected]"
});

// Find all customers whose last name is "Bond"
customers.Where(x => x.LastName == "Bond");

// Find all customers whose last name is Bond OR whose age is greater than 65
customers.Where(x => x.LastName == "Bond" || x.Age > 65);

// Find all customers whose last name is Bond AND whose first name is James
customers.Where(x => x.LastName == "Bond" && x.FirstName == "James");

// Find all customers with the nickname of Jim
customer.Where(x=>x.NickNames.Contains("Jim"));

πŸ–© Aggregations

We can also run aggregations on the customer object, again using expressions in LINQ:

// Get our average customer age
customerAggregations.Average(x => x.RecordShell.Age);

// Format customer full names
customerAggregations.Apply(x => string.Format("{0} {1}", x.RecordShell.FirstName, x.RecordShell.LastName),
      "FullName");

// Get each customer's distance from the Mall of America
customerAggregations.Apply(x => ApplyFunctions.GeoDistance(x.RecordShell.Home, -93.241786, 44.853816),
      "DistanceToMall");

πŸ“š Documentation

This README just scratches the surface. You can find a full tutorial on the Redis Developer Site. All the summary docs for this library can be found on the repo's github page.

⛏️ Troubleshooting

If you run into trouble or have any questions, we're here to help!

First, check the FAQ. If you don't find the answer there, hit us up on the Redis Discord Server.

✨ Redis Stack

Redis OM can be used with regular Redis for Object mapping and getting objects by their IDs. For more advanced features like indexing, querying, and aggregation, Redis OM is dependent on the Redis Stack platform, a collection of modules that extend Redis.

Why this is important

Without Redis Stack, you can still use Redis OM to create declarative models backed by Redis.

We'll store your model data in Redis as Hashes, and you can retrieve models using their primary keys.

So, what won't work without Redis Stack?

  1. You won't be able to nest models inside each other.
  2. You won't be able to use our expressive queries to find object -- you'll only be able to query by primary key.

So how do you get Redis Stack?

You can use Redis Stack with your self-hosted Redis deployment. Just follow the instructions for Installing Redis Stack.

Don't want to run Redis yourself? Redis Stack is also available on Redis Cloud. Get started here.

❀️ Contributing

We'd love your contributions! If you want to contribute please read our Contributing document.

❀️ Our Contributors

More Repositories

1

redis

Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps.
C
66,875
star
2

go-redis

Redis Go client
Go
19,891
star
3

node-redis

Redis Node.js client
TypeScript
16,841
star
4

ioredis

πŸš€ A robust, performance-focused, and full-featured Redis client for Node.js.
TypeScript
14,344
star
5

redis-py

Redis Python client
Python
12,506
star
6

jedis

Redis Java client
Java
11,766
star
7

hiredis

Minimalistic C client for Redis >= 1.2
C
6,197
star
8

lettuce

Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
Java
5,352
star
9

redis-rb

A Ruby client library for Redis
Ruby
3,963
star
10

rueidis

A fast Golang Redis client that supports Client Side Caching, Auto Pipelining, Generics OM, RedisJSON, RedisBloom, RediSearch, etc.
Go
2,327
star
11

redis-doc

Redis documentation source code for markdown and metadata files, conversion scripts, and so forth
Shell
2,310
star
12

redis-om-node

Object mapping, and more, for Redis and Node.js. Written in TypeScript.
TypeScript
1,158
star
13

docker-library-redis

Docker Official Image packaging for Redis
Shell
1,117
star
14

redis-om-python

Object mapping, and more, for Redis and Python
Python
1,093
star
15

redis-io

Application running http://redis.io
Ruby
637
star
16

redis-om-spring

Spring Data Redis extensions for better search, documents models, and more
Java
599
star
17

hiredis-py

Python wrapper for hiredis
C
495
star
18

hiredis-rb

Ruby wrapper for hiredis
Ruby
319
star
19

hiredis-node

Node wrapper for hiredis
JavaScript
305
star
20

riot

🧨 Get data in & out of Redis with RIOT
Java
273
star
21

NRedisStack

Redis Stack .Net client
C#
220
star
22

redis-vl-python

Redis Vector Library (RedisVL) interfaces with Redis' vector database for realtime semantic search, RAG, and recommendation systems.
Python
218
star
23

redis-rcp

Redis Change Proposals
136
star
24

redis-hashes

Redis tarball SHA1 hashes
92
star
25

lettucemod

Java client for Redis Modules
Java
50
star
26

spring-batch-redis

Spring Batch extension for Redis
Java
47
star
27

redis-specifications

A bin for Redis' specs
38
star
28

minipilot

MiniPilot is a GenAI-assisted chatbot backed by Redis. Chat with your documents
HTML
31
star
29

redis-benchmarks-specification

The Redis benchmarks specification describes the cross-language/tools requirements and expectations to foster performance and observability standards around redis related technologies. Members from both industry and academia, including organizations and individuals are encouraged to contribute.
Python
29
star
30

librdb

Redis RDB file parser, with JSON, RESP and RDB-loader extensions
C
23
star
31

docs

Documentation for Redis, Redis Cloud, and Redis Enterprise
Python
23
star
32

redis-debian

Debian packaging
Shell
18
star
33

redis-snap

A repository for snap packaging
10
star
34

redis-website

HTML
9
star
35

Redis-Insight-Guides

Learn modern data models and data processing tools bundled in Redis Stack to build real-time applications with the speed and stability of Redis.
5
star
36

redis-clinterwebz

Python
4
star
37

redis-extra-ci

4
star
38

riot-docker

Dockerfile
2
star
39

redis-rpm

Shell
2
star
40

scoop

1
star
41

homebrew-tap

Homebrew tap for Redis organization
Ruby
1
star