如何定位Mongoose抛出的MongoServerError对应的原始代码位置和关联查询
Mongoose 报错调用栈缺失与慢查询定位配置方案
报错根因说明
你收到的Cannot run getMore on cursor错误本质是:创建游标时使用的会话已经提前销毁,通常出现在带会话/事务的游标遍历场景中,还未完成游标遍历就主动结束了会话,导致后续拉取游标数据时校验失败。
一、配置Mongoose输出业务代码调用栈与对应查询语句
- 开启长栈追踪:Mongoose默认关闭长栈优化性能,开启后会保留业务层到驱动层的完整调用链路,在初始化连接前添加配置:
mongoose.set('stackTraceLimit', 100); - 开启Node.js异步栈追踪:启动服务时添加启动参数,可完整保留异步调用链路,TypeScript项目可配合source map映射到源码位置:
node --stack-trace-limit=100 --enable-source-maps your-app.js - 开启Mongoose调试模式:会实时打印所有执行的查询语句、参数、执行时间,报错时可直接匹配到对应业务查询:
mongoose.set('debug', true);
也可以自定义debug的输出格式,增加调用栈打印:mongoose.set('debug', (collectionName, method, query, doc, options) => { const stack = new Error().stack.split('\n').slice(2).join('\n'); console.log(`[Mongoose] ${collectionName}.${method} 查询参数: ${JSON.stringify(query)}\n调用栈: ${stack}`); }); - 所有查询添加业务标识:调用查询时使用
comment()方法传入业务场景标识,该标识会同步到MongoDB报错日志、慢查询日志中,可直接定位业务位置:
示例:User.find({ age: { $gt: 18 } }).comment('用户模块-获取成年用户列表')
二、定位MongoDB慢查询对应的业务代码
- 优先用上述
comment()方法添加业务标识,MongoDB自带的慢查询日志会完整展示该注释内容,无需额外配置即可直接匹配到对应业务代码。 - 全局挂载慢查询捕获钩子:可自定义耗时阈值,命中时直接打印查询内容和对应调用栈:
// 全局插件,所有Schema都会生效 mongoose.plugin((schema) => { const monitorMethods = ['find', 'findOne', 'findById', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'aggregate']; monitorMethods.forEach(method => { schema.pre(method, function() { this._startTime = Date.now(); this._queryStack = new Error().stack; }); schema.post(method, function(res, next) { const cost = Date.now() - this._startTime; // 可根据业务需求调整阈值,单位ms if (cost > 300) { console.warn( `Mongo慢查询: ${this.model.collection.name}.${method}\n` + `查询条件: ${JSON.stringify(this.getFilter())}\n` + `耗时: ${cost}ms\n` + `调用栈: ${this._queryStack}` ); } next(); }); }); });
内容的提问来源于stack exchange,提问作者rStorms
相关产品推荐
相关产品推荐

