Mongoose + Redis. Автоматизация кэширования за 5 минут

Kate

Administrator
Команда форума
  1. Mongoose представляет специальную ODM-библиотеку (Object Data Modelling) для работы с MongoDB, которая позволяет сопоставлять объекты классов и документы коллекций из базы данных.
  2. Redis (Remote Dictionary Server)- это быстрое хранилище данных типа «ключ‑значение» в памяти, активно используемое в разработке с целью повышения производительности сервисов
  3. В рамках данного гайда мы рассмотрим связку Mongoose + Redis и посмотрим, как обеспечить максимально удобное взаимодействие между ними
Шаг 1. Установка пакетов

yarn add redis mongoose

Шаг 2. Конфигурация Redis.

const redisUrl = process.env.REDIS_CACHE_URL
const client = redis.createClient(redisUrl)
client.get = util.promisify(client.get)
Шаг 3. Формирование ключа

Одна из важных задач кэширования - составление ключа, под которым кэшировать данные. В контексте mongoose мы можем очень эффективно использовать свойства и методы прототипа Query, которые позволяют получить основную структуру запроса:

  1. mongooseCollection.name - наименование коллекции
  2. getQuery - возвращает список фильтров запроса ( например, where)
  3. op - наименование операции (например, find)
  4. options - опции запроса ( например, limit )
const key = JSON.stringify(
{
...this.getQuery(),
collection: this.mongooseCollection.name,
op: this.op,
options: this.options
}
)
Шаг 4. Основная логика

Теперь, определив паттерн формирования ключей и установив соединение с Redis, можно перейти к имплементации основной логики кэширования:

  1. Пытаемся получить данные по ключу
  2. Если удалось, то возвращаем десериализованные данные
  3. Если же данные еще не были закэшированы, то выполняем запрос в базу данных
  4. Кэшируем полученные данные
  5. Возвращаем результат
const cacheValue = await client.get(key)
if ( cacheValue ) return JSON.parse(cacheValue)

const result = await exec.apply(this, arguments)
if ( result ) {
await client.set(key, JSON.stringify(result))
}

return result
Шаг 5. Собираем все вместе

Последним шагом, чтобы собрать весь функционал вместе, будет переопределение метода exec, чтобы кэширование применялось «из коробки»:

module.exports =
{
applyMongooseCache() {

const redisUrl = process.env.REDIS_CACHE_URL
const client = redis.createClient(redisUrl)
client.get = util.promisify(client.get)
const exec = mongoose.Query.prototype.exec

mongoose.Query.prototype.exec = async function () {

const key = JSON.stringify(
{
...this.getQuery(),
collection: this.mongooseCollection.name,
op: this.op,
options: this.options
}
)

const cacheValue = await client.get(key)
if ( cacheValue ) return JSON.parse(cacheValue)

const result = await exec.apply(this, arguments)

if ( result ) {
await client.set(key, JSON.stringify(result))
}

return result
}
},
}
Теперь остается только вызвать функцию applyMongooseCache при старте Вашего приложения.

Шаг 6. Docker-compose для локального запуска сервисов

Для тестирования данного функционала нам нужны два сервиса:

  1. MongoDB
  2. Redis
  3. Mongo Express - система администрирования MongoDB
  4. Redis admin - система администрирования Redis
version: '3'
services:
mongo:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: root
ports:
- 27017:27017

mongo-express:
image: mongo-express:0.54
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: root
depends_on:
- mongo

redis:
image: redis
ports:
- 6379:6379

redis-admin:
image: erikdubbelboer/phpredisadmin
ports:
- 8085:80
depends_on:
- redis
environment:
REDIS_1_HOST: redis
REDIS_1_NAME: redis
REDIS_1_PORT: 6379
Используя данную базовую конфигурацию, Вы сможете получить к сервисам локальный доступ на 27017(mongo) и 6379 (Redis) портах.

Соответственно, системы администрирования будут доступны на 8081 ( mongo-express) и 8085 (Redis admin) портах.

Ссылка на репозиторий: https://github.com/IAlexanderI1994/mongoose-redis

 
Сверху