mongodb(mongoose-redis-cache)
在传统的项目中,我们经常会用到缓存来优化数据库的读取,比如java中,我们利用spring的AOP能力,在读写数据库前增加对缓存的操作。
在node与mongodb的项目中也仍然会存在类似问题,本文参考了mongoose-redis-cache这个插件。
https://github.com/conancat/mongoose-redis-cache
该插件还不太完善,但基本的思路是很简单的,初始化一个redis客户端,然后重写mongoose的exec方法,将exec的参数设置为redis的key,将数据库返回的结果设置为对应的value。
每次操作时优先读取redis。
代码如下:
// Generated by CoffeeScript 1.5.0 var mongooseRedisCache, redis, _; redis = require("redis"); _ = require("underscore"); mongooseRedisCache = function(mongoose, options, callback) { var client, host, pass, port, redisOptions; if (options == null) { options = {}; } host = options.host || ""; port = options.port || ""; pass = options.pass || ""; redisOptions = options.options || {}; mongoose.redisClient = client = redis.createClient(port, host, redisOptions); if (pass.length > 0) { client.auth(pass, function(err) { if (callback) { return callback(err); } }); }
//这里做了改动,原来是execFind,在我当前的Mongoose版本下无法使用 mongoose.Query.prototype._exec = mongoose.Query.prototype.exec; mongoose.Query.prototype.exec = function(callback) { var cb, expires, fields, key, model, query, schemaOptions, self; self = this; model = this.model; query = this._conditions; options = this._optionsForExec(model); fields = _.clone(this._fields); schemaOptions = model.schema.options; expires = schemaOptions.expires || 60; if (!schemaOptions.redisCache && options.lean) { return mongoose.Query.prototype._exec.apply(self, arguments); } key = JSON.stringify(query) + JSON.stringify(options) + JSON.stringify(fields); cb = function(err, result) { var docs; if (err) { return callback(err); } if (!result) { return mongoose.Query.prototype._exec.call(self, function(err, docs) { var str; if (err) { return callback(err); } str = JSON.stringify(docs); client.set(key, str); client.expire(key, expires); return callback(null, docs); }); } else { docs = JSON.parse(result); return callback(null, docs); } }; client.get(key, cb); return this; }; }; module.exports = mongooseRedisCache;
写测试用例如下:
var mongoose = require('mongoose'); var async = require('async'); var mongooseRedisCache = require("mongoose-redis-cache"); mongooseRedisCache(mongoose); var Schema = mongoose.Schema; mongoose.connect('mongodb://localhost/cachetest'); var user = new Schema({ username:{ type:String, index:true }, password:String }); user.set('redisCache', true); var userModel = mongoose.model('user', user); var entity = new userModel({ username:'fredric', password:'sinny' }); var users = []; for(var i = 0; i < 1000; i++){ users.push({ username:'fredric' + i, password:'sinny' + i }); } function testCache(){ function datainit(item,cb){ var entity = new userModel(item); entity.save(function(err){ cb(err); }); } async.mapSeries(users, datainit, function(err, results){ console.log('datainit finished'); var timestamp = new Date().valueOf(); var round = []; for(var i = 0; i < 2000; i++){ round.push(i); } //利用缓存 function test(item,cb){ query = userModel.find({'username':'fredric101'}); query.lean(); query.exec(function(err, result){ cb(err); }); } //不利用缓存 function test_nocache(item,cb){ query = userModel.find({}).setOptions({nocache: true}); query.where("username", "fredric101"); query.exec(function(err, result){ cb(err); }); } async.mapSeries(round, test_nocache, function(err, results){ console.log(new Date().valueOf() - timestamp); }); }); } testCache();
测试结果还是比较明显的,在我本地笔记本上(安装redis + mongodb),上述测试用例执行:
1、无缓存、无索引:21501ms
2、无缓存、有索引:1966ms
3、有缓存、有索引:281ms
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)