Mongoose представляет специальную ODM-библиотеку (Object Data Modelling) для работы с MongoDB, которая позволяет сопоставлять объекты классов и документы коллекций из базы данных.
Redis (Remote Dictionary Server)- это быстрое хранилище данных типа «ключ‑значение» в памяти, активно используемое в разработке с целью повышения производительности сервисов
В рамках данного гайда мы рассмотрим связку 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, которые позволяют получить основную структуру запроса:
mongooseCollection.name - наименование коллекции
getQuery - возвращает список фильтров запроса ( например, where)
op - наименование операции (например, find)
options - опции запроса ( например, limit )
const key = JSON.stringify(
{
...this.getQuery(),
collection: this.mongooseCollection.name,
op: this.op,
options: this.options
}
)
Шаг 4. Основная логика
Теперь, определив паттерн формирования ключей и установив соединение с Redis, можно перейти к имплементации основной логики кэширования:
Пытаемся получить данные по ключу
Если удалось, то возвращаем десериализованные данные
Если же данные еще не были закэшированы, то выполняем запрос в базу данных
Кэшируем полученные данные
Возвращаем результат
const cacheValue = await client.get(key)
if ( cacheValue ) return JSON.parse(cacheValue)
const result = await exec.apply(this, arguments)
if ( result ) {
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 ) {
client.set(key, JSON.stringify(result))
}
return result
}
},
}
Теперь остается только вызвать функцию applyMongooseCache при старте Вашего приложения.
Шаг 6. Docker-compose для локального запуска сервисов
Для тестирования данного функционала нам нужны два сервиса:
MongoDB
Redis
Mongo Express - система администрирования MongoDB
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
Благодарю Вас за прочтение. Буду рад Вашим вопросам и комментариям.