@alpha018/nestjs-redisom
v1.1.0
Published
A NestJS module for RedisOM, providing a structured way to use Redis Stack JSON/Search features.
Downloads
182
Maintainers
Readme
NestJS RedisOM
Description
This library seamlessly integrates RedisOM into NestJS, offering:
- Decorator-based Schema Definition: Define your entities using
@Schemaand@Prop. - Repository Injection: Inject repositories directly into your services using
@InjectRepository. - Seamless Connection: Configure your Redis connection globally with
forRootorforRootAsync.
Installation
npm install @alpha018/nestjs-redisom redis-om redisQuick Start
1. Define an Entity
Use the @Schema() decorator to define your entity and @Prop() for properties. Extends BaseEntity to easily access the auto-generated ID.
import { Schema } from 'nestjs-redisom';
import { Prop } from 'nestjs-redisom';
import { BaseEntity } from 'nestjs-redisom';
@Schema()
export class CatEntity extends BaseEntity {
@Prop()
name: string;
@Prop()
age: number;
}Note: For all available property decorators, indexing options, and schema definitions, see the Wiki: Defining Structures.
2. Import the Module
Register RedisOmModule in your root AppModule and register your entities with forFeature.
import { Module } from '@nestjs/common';
import { RedisOmModule } from 'nestjs-redisom';
import { CatEntity } from './cat.entity';
@Module({
imports: [
RedisOmModule.forRoot({
url: 'redis://localhost:6379'
}),
RedisOmModule.forFeature([CatEntity]),
],
})
export class AppModule {}Note: For advanced connection setups, environmental validation, and asynchronous options, see the Wiki: Configuration.
3. Usage in a Service
Inject the repository to save and search for entities.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from 'nestjs-redisom';
import { Repository } from 'redis-om';
import { CatEntity } from './cat.entity';
@Injectable()
export class CatsService {
constructor(
@InjectRepository(CatEntity) private readonly catRepo: Repository<CatEntity>,
) {}
async create(name: string, age: number) {
const entity = new CatEntity();
entity.name = name;
entity.age = age;
return await this.catRepo.save(entity);
}
async findAll() {
return await this.catRepo.search().return.all();
}
}Note: To learn about all search capabilities and query building, see the Wiki: Searching.
Advanced Usage
1. Nested Typed Objects
You can define nested objects using classes and the @Prop({ type: () => Class }) syntax. This allows Redis OM to automatically generate the correct schema fields for your nested data.
How it works:
The library flattens nested properties into the Redis schema using the format parentProperty_childProperty (underscore separator). This allows you to index and search deeply nested fields without complex JSON path syntax.
Define the Embedded Class:
export class Address {
@Prop({ indexed: true })
street: string;
@Prop({ indexed: true })
city: string; // Will become 'address_city' in the schema
}Use in Parent Entity:
@Schema({ dataStructure: 'JSON' })
export class Person extends BaseEntity {
@Prop()
name: string;
@Prop({ type: () => Address })
address: Address;
}Search using flattened/nested fields:
Since the schema uses flattened keys, you query them using the underscore syntax:
// Search for persons where address.city is 'New York'
const results = await this.personRepo.search()
.where('address_city' as any) // Use the flattened key
.eq('New York')
.return.all();Note: Discover more about embedded objects and array structures in the Wiki: Defining Structures.
2. Custom IDs
You can explicitly set the ID when saving an entity if you don't want to use the auto-generated ULID. This is useful for using existing IDs (like UUIDs, emails, or external system IDs).
// Using a UUID
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
await this.catRepo.save(id, entity);
// Using a custom string
await this.catRepo.save('unique-custom-id', entity);Note: Read more about identifier strategies in the Wiki: Defining Structures.
3. TTL (Time To Live)
You can set an expiration time (in seconds) for an entity. The key will automatically be deleted from Redis after the specified time.
const id = 'temp-session-123';
await this.catRepo.save(id, sessionEntity);
// Expire after 60 seconds
await this.catRepo.expire(id, 60);Note: See entity expiration patterns in the Wiki: Defining Structures.
4. TLS Connection (Production / Cloud)
For secure connections (e.g., AWS ElastiCache, Redis Cloud), use the rediss:// protocol and provide TLS options in the socket configuration.
Static Configuration:
import * as fs from 'fs';
RedisOmModule.forRoot({
url: 'rediss://your-redis-instance:6380',
socket: {
tls: true,
rejectUnauthorized: false, // Set to true if using a public CA
// ca: fs.readFileSync('path/to/ca.pem'), // Optional: Load custom CA
},
})Async Configuration (e.g., using ConfigService):
RedisOmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
url: config.get('REDIS_URL'), // e.g., 'rediss://...'
socket: {
tls: true,
rejectUnauthorized: config.get('REDIS_TLS_REJECT_UNAUTHORIZED') === 'true',
},
}),
})Note: Find more cloud connection examples in the Wiki: Configuration.
5. Redis Cluster (Cluster Mode Enabled)
nestjs-redisom natively supports connecting to a Redis Cluster using the underlying createCluster functionality of Node-Redis.
Instead of providing a single url, you provide an array of rootNodes:
RedisOmModule.forRoot({
rootNodes: [
{ url: 'redis://redis-cluster-node-1:7000' },
{ url: 'redis://redis-cluster-node-2:7000' }
],
defaults: {
password: 'your-cluster-password'
}
})Note: For full details on how the Node-Redis client uses these initial nodes for cluster auto-discovery (
CLUSTER SLOTS), please refer to the Configuration Wiki.
Features
- Schema Factory: Automatically generates RedisOM schemas from your class metadata.
- Nested Objects: Support for typed nested objects with automatic schema flattening.
- Async Configuration: Supports
useFactory,useClass, anduseExistingfor configuration. - Validation: Compatible with
class-validator(standard NestJS practice).
Performance & Search Mechanics
This library leverages RediSearch (module of Redis Stack), meaning searches are efficient and non-blocking.
1. How Search Works
When you use @Prop({ indexed: true }), Redis OM creates an Inverted Index.
- Search:
repo.search()...queries this index directly. It does NOT perform a linear scan (SCAN command) over the keyspace. - Complexity: Searches are typically O(K) (where K is the number of results) or O(log N) for range queries. Retrieving by ID is O(1).
Search Complexity by Type
| Data Type | Operation | Complexity | Notes |
| :--- | :--- | :--- | :--- |
| ID | Retrieve (fetch) | O(1) | Direct key access (fastest). |
| Tag / String | Exact Match (eq) | O(K) | K = number of results returned. |
| Numeric / Date | Range (gt, lt, between) | O(log N + K) | Uses sorted sets/trees. efficient for ranges. |
| Text | Full-Text (matches) | O(M + K) | M = number of terms/words being searched. |
| Geo | Radius / Polygon | O(K + log N) | Geospacial indexing. |
2. Resource Usage
- Memory (RAM): Indexes consume additional memory. Best Practice: Only index fields that you intend to filter by.
- CPU: Search operations are highly optimized. Initial indexing of a large existing dataset may temporarily consume CPU, but incremental updates (
save) are lightweight.
Resources
Check out a few resources that may come in handy when working with NestJS:
- Visit the NestJS Documentation to learn more about the framework.
- Visualize your application graph and interact with the NestJS application in real-time using NestJS Devtools.
Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.
Stay in touch
- Author - Tomás Alegre
License
NestJS RedisOM is MIT licensed.
