ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Mongoose 连接 MongoDB 报 DeprecationWarning?一份配置骨架帮你理清

Mongoose 连接 MongoDB 报 DeprecationWarning?一份配置骨架帮你理清 1. 启动项目就弹 DeprecationWarning先别急着关掉如果你正在用 Node.js Mongoose 连 MongoDB大概率在控制台见过这种黄色警告DeprecationWarning: current URL string parser is deprecated或者collection.ensureIndex is deprecated、collection.findAndModify is deprecated。它们不影响进程启动但每次npm run dev都刷一屏看着很烦而且有些警告背后确实对应着未来版本会被移除的 API拖着不处理升级驱动时容易直接报错。这篇面向的是刚接触 Mongoose 的同学也适合手上有个老项目、想一次性把警告收敛干净的开发者。核心思路很简单Mongoose 5.x 默认调用的是 MongoDB Node.js 驱动里一批旧接口驱动把这些接口标记为弃用并提供了开关让你切到新实现。你要做的不是逐个去猜而是先分清哪些警告靠连接选项就能消掉哪些必须改代码里的方法名。我会先给一份可以直接复制的连接配置骨架再逐项解释每个选项对应哪条警告、怎么验证它真的生效了最后把remove()、update()、count()这类必须改代码的情况单独拎出来讲。整个过程不需要你重装数据库也不需要改连接字符串的格式。需要说明的是下面所有配置都基于 Mongoose 5.x 的官方弃用说明整理Mongoose 6 之后部分选项已经变成默认行为如果你用的是 6 及以上版本看到选项被忽略是正常的可以直接跳到代码替换那一节。2. 前置准备确认版本再决定配置策略在动手改配置之前先花一分钟确认你当前的版本组合因为 Mongoose 5 和 6 对弃用选项的处理完全不同。打开项目根目录执行npm ls mongoose mongodb你会看到类似这样的输出├── mongoose5.13.20 └─┬ mongodb3.7.4这里的关键是 Mongoose 主版本号。如果是 5.x那么useNewUrlParser、useUnifiedTopology、useCreateIndex、useFindAndModify这些选项都还有意义需要显式设置。如果是 6.x 及以上Mongoose 已经把新解析器和新拓扑引擎设为默认useNewUrlParser之类的选项会被直接忽略你设了也不会报错但也不起作用此时警告通常来自你自己代码里调用了remove()、update()、count()这些旧方法。确认完版本再确认你的连接代码写在哪。常见的有三种位置入口文件app.js或server.js里直接mongoose.connect()单独的config/db.js里封装了连接函数或者用mongoose.createConnection()做多连接。不管哪种配置骨架的写法是一致的区别只是全局mongoose.set()和连接级选项的取舍。我建议优先用连接级选项也就是把配置写在mongoose.connect(uri, options)的第二个参数里。原因是全局mongoose.set()会影响进程内所有连接如果你后面加了多数据源全局设置容易互相干扰。连接级选项只作用于当前连接边界清晰排查问题时也更容易定位。3. 可复制的连接配置骨架下面这份骨架可以直接贴到你的config/db.js里把MONGO_URI换成你自己的连接字符串即可。我按「连接选项 全局兜底」两层来写注释里标了每个选项对应哪条警告。const mongoose require(mongoose); // 全局兜底仅对 Mongoose 5.x 生效6.x 会自动忽略 mongoose.set(useNewUrlParser, true); mongoose.set(useUnifiedTopology, true); mongoose.set(useCreateIndex, true); mongoose.set(useFindAndModify, false); const MONGO_URI process.env.MONGO_URI || mongodb://127.0.0.1:27017/demo; async function connectDB() { try { await mongoose.connect(MONGO_URI, { // 使用新的连接字符串解析器消除 URL string parser 警告 useNewUrlParser: true, // 使用新的拓扑引擎消除 Server Discovery 相关警告 useUnifiedTopology: true, // 用 createIndex 替代 ensureIndex消除索引相关警告 useCreateIndex: true, // 让 findOneAndUpdate 走驱动原生实现消除 findAndModify 警告 useFindAndModify: false, // 连接池大小按需调整 maxPoolSize: 10, // 选主超时避免网络抖动时长时间挂起 serverSelectionTimeoutMS: 5000, }); console.log(MongoDB connected:, mongoose.connection.host); } catch (err) { console.error(MongoDB connection failed:, err.message); process.exit(1); } } module.exports connectDB;几个容易踩的点单独说一下。useUnifiedTopology虽然不在你贴的 excerpt 里但它是 Mongoose 5.7 之后最常见的另一条警告来源报错文本是DeprecationWarning: current Server Discovery and Monitoring engine is deprecated加上它就一起消掉了。maxPoolSize在 Mongoose 5 里旧写法是poolSize如果你看到poolSize is deprecated的提示换成maxPoolSize即可。另外注意useFindAndModify的值是false不是true。这一点很多人会设反。它的含义是「不要用驱动里那个旧的 findAndModify 封装」所以设成false才是启用新行为。设成true反而会保留旧路径警告照旧。如果你用的是mongoose.createConnection()把同样的 options 对象传进去就行const conn mongoose.createConnection(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false, });4. 逐项验证确认警告真的消失了配置写完不代表警告就没了得实际跑一遍看输出。最直接的验证方式是启动你的服务观察控制台。但更严谨的做法是写一个最小验证脚本排除业务代码干扰。新建一个verify.jsconst mongoose require(mongoose); mongoose.set(useNewUrlParser, true); mongoose.set(useUnifiedTopology, true); mongoose.set(useCreateIndex, true); mongoose.set(useFindAndModify, false); const schema new mongoose.Schema({ name: { type: String, index: true }, age: Number, }); const User mongoose.model(User, schema); (async () { await mongoose.connect(mongodb://127.0.0.1:27017/verify_demo, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false, }); console.log(connected); // 触发索引创建验证 useCreateIndex await User.init(); // 触发 findOneAndUpdate验证 useFindAndModify await User.findOneAndUpdate({ name: a }, { age: 1 }, { upsert: true }); console.log(done, check warnings above); await mongoose.disconnect(); })();运行node verify.js如果配置正确控制台应该只有connected和done两行没有任何DeprecationWarning。如果还有警告把完整警告文本复制出来对照下一节的排查表定位。这里有个细节User.init()会等待索引构建完成是验证useCreateIndex是否生效的关键动作。如果你不调用它索引可能延迟创建警告也就不一定在启动阶段出现容易误判成「已经修好了」。5. 本篇常见错排查警告还在但选项明明设了。先确认 Mongoose 版本。6.x 会忽略这些选项如果你在 6.x 上看到findAndModify警告那多半是代码里还在用findOneAndUpdate的旧调用方式或者某个依赖库内部在用。用npm ls mongoose确认版本再决定是降级到 5.x 还是直接改代码。useFindAndModify设成 true 反而报错。前面说过这个选项要设false。设true是保留旧行为警告不会消失。检查你的配置里有没有写反。remove()的警告消不掉。这个选项管不了必须改代码。Model.remove()要换成deleteMany()如果原来带了{ single: true }换成deleteOne()。批量替换时注意区分这两种情况别一股脑全换成deleteMany。update()的警告消不掉。同理update()要按语义拆成updateOne()、updateMany()或replaceOne()。原来带{ multi: true }的换updateMany()带{ overwrite: true }的换replaceOne()其余默认换updateOne()。count()的警告消不掉。带过滤条件的count(filter)换成countDocuments(filter)不带参数的count()换成estimatedDocumentCount()。链式调用find().count().exec()也要相应改成find().countDocuments().exec()或find().estimatedDocumentCount().exec()。GridStore 警告。如果你用了gridfs-stream会看到GridStore is deprecated。这个库依赖了旧驱动类建议换成mongoose.mongo.GridFSBucket用openUploadStream替代原来的createWriteStream。排查时有个通用技巧把警告文本里的关键词比如ensureIndex、findAndModify、collection.remove直接搜 Mongoose 官方 deprecations 页面每条警告都有对应的选项或替换方法比盲目试错快得多。6. 配置收敛之后把验证动作固定下来警告清干净只是第一步真正省心的是把「启动时无弃用警告」变成一条可回归的检查。我的做法是在 CI 里加一个启动脚本把 stderr 里的DeprecationWarning当成失败信号这样以后升级依赖或有人提交旧写法时能第一时间发现。如果你在本地调试时想快速验证某个模型方法会不会触发警告可以临时把process.on(warning, ...)挂上把警告堆栈打出来定位到具体是哪一行代码调用的。这比看一屏黄色文字有用得多。配置骨架本身不复杂难的是分清「选项能解决的」和「必须改代码的」这两类。选项类的一次性设好就行代码类的建议趁这次一起替换掉尤其是remove()和update()它们在 Mongoose 6 之后已经彻底移除早改早省事。如果你在接入过程中需要集中管理多个项目的连接配置或者想用统一的入口调试模型调用可以到 TaoToken 的模型对话页面先跑通请求链路再回到本地收敛配置https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。接入文档里也有连接参数和鉴权的完整说明配合这篇的配置骨架一起看能少走不少弯路https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进