Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Want to use Nestjs with other Redis command

I try to implement nestjs backend and redis as caching. I can do it according to the official document https://docs.nestjs.com/techniques/caching#in-memory-cache.

I use the package cache-manager-redis-store and the code in app.module.ts is as shown below.

import { Module, CacheModule } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import * as redisStore from 'cache-manager-redis-store';
import * as Joi from 'joi';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    CacheModule.registerAsync({
      imports: [
        ConfigModule.forRoot({
          validationSchema: Joi.object({
            REDIS_HOST: Joi.string().default('localhost'),
            REDIS_PORT: Joi.number().default(6379),
            REDIS_PASSWORD: Joi.string(),
          }),
        }),
      ],
      useFactory: async (configService: ConfigService) => ({
        store: redisStore,
        auth_pass: configService.get('REDIS_PASSWORD'),
        host: configService.get('REDIS_HOST'),
        port: configService.get('REDIS_PORT'),
        ttl: 0,
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

With this setting, I can use get and set as expected but I want to use other redis command such as hget and zadd. Unfortunately, I cannot find the guide anywhere.

I think there must be a way since cache-manager-redis-store package said that it just passing the configuration to the underlying node_redis package. And node-redis package can use those fancy redis commands.

Would be appreciated if you have solutions.

like image 513
jelly Avatar asked Aug 31 '25 16:08

jelly


1 Answers

Thank you both Micael Levi and Hamidreza Vakilian for the help. I did more research and found my solution so I will share it for other people have the same problem.

It seem cache-manager-redis-store allow only normal redis operation and if you want to use more, you have to access cacheManager.store.getClient() as Micael suggest.

Cache interface got no getClient but RedisCache had! The problem is RedisCache interface inside cache-manager-redis-store package don't export those interface for outsider.

The easiest way to fix this is to create redis.interface.ts or whatever name for your own.

import { Cache, Store } from 'cache-manager';
import { RedisClient } from 'redis';

export interface RedisCache extends Cache {
  store: RedisStore;
}

export interface RedisStore extends Store {
  name: 'redis';
  getClient: () => RedisClient;
  isCacheableValue: (value: any) => boolean;
}

Now you can replace Cache with RedisCache interface.

The usage will be as follows.

import {
  CACHE_MANAGER,
  Inject,
  Injectable,
} from '@nestjs/common';
import { RedisClient } from 'redis';
import { RedisCache } from './interface/redis.interface';

@Injectable()
export class RedisService {
  private redisClient: RedisClient;
  constructor(@Inject(CACHE_MANAGER) private cacheManager: RedisCache) {
    this.redisClient = this.cacheManager.store.getClient();
  }

  hgetall() {
    this.redisClient.hgetall('mykey', (err, reply) => {
      console.log(reply);
    })
  }
}

Note that these redisClient commands do not return value so you have to use callback to get the value.

As you can see that the answer is in callback structure, I prefer await and async more so I did a little more work.

import {
  BadRequestException,
  CACHE_MANAGER,
  Inject,
  Injectable,
} from '@nestjs/common';
import { RedisClient } from 'redis';
import { RedisCache } from './interface/redis.interface';

@Injectable()
export class RedisService {
  private redisClient: RedisClient;
  constructor(@Inject(CACHE_MANAGER) private cacheManager: RedisCache) {
    this.redisClient = this.cacheManager.store.getClient();
  }

  async hgetall(key: string): Promise<{ [key: string]: string }> {
    return new Promise<{ [key: string]: string }>((resolve, reject) => {
      this.redisClient.hgetall(key, (err, reply) => {
        if (err) {
          console.error(err);
          throw new BadRequestException();
        }
        resolve(reply);
      });
    });
  }
}

By using promise, I can get the answer as if the function return. The usage is as follows.

import { Injectable } from '@nestjs/common';
import { RedisService } from './redis.service';

@Injectable()
export class UserService {
  constructor(private readonly redisService: RedisService) {}

  async getUserInfo(): Promise<{ [key: string]: string }> {
    const userInfo = await this.redisService.hgetall('mykey');
    return userInfo;
  }
}
like image 193
jelly Avatar answered Sep 02 '25 22:09

jelly