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
Благодарю Вас за прочтение. Буду рад Вашим вопросам и комментариям.
