首页 / 资讯中心 / 文章详情

NodeJS连接MongoDB数据库实战:Mongoose数据校验与增删查改全流程(TaoToken统一Key接入)

NodeJS连接MongoDB数据库实战:Mongoose数据校验与增删查改全流程(TaoToken统一Key接入) ★ FEATURED ARTICLE
1. NodeJS 连接 MongoDB 总踩坑先把 Mongoose 这套 ODM 数据校验链路跑通如果你正在搜「NodeJS 连接 MongoDB 教程」或者「Mongoose 数据校验怎么写」大概率已经遇到过这几种情况原生驱动写起来一堆回调、字段想加个必填校验得自己手写 if、连接一跑就弹useNewUrlParser警告、增删查改的接口散落在各处不好维护。这篇就按我实际落地的顺序把 NodeJS Mongoose 从连接、Schema 校验到 CRUD 封装整条链路走一遍代码都能直接复制。Mongoose 是什么简单说它是 MongoDB 的 ODM对象文档模型把 JS 对象映射成数据库文档JSON 转 BSON 这层它帮你做了。它能做什么给集合定义 Schema 结构、对写入数据做类型和必填校验、用中间件挂业务逻辑、把原生驱动的回调包成更好用的 API。适合谁正在用 NodeJS 做后端、需要往 MongoDB 里存结构化数据、又不想在业务代码里到处写校验的开发者。我试过直接用原生mongodb驱动写一个用户注册接口光校验手机号格式、判断字段有没有传就写了二十多行换成 Mongoose 之后 Schema 里几行就声明完了。下面按「连接 → 校验 → 增删查改 → 排错」的顺序来每一步都有可复制的代码。另外提一句凭证管理项目里如果还要调大模型接口做数据清洗、内容生成之类的辅助逻辑Key 散落在各个.env里很容易乱。我现在的做法是用 TaoToken 统一管这类调用凭证官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 可以先了解下后面第 2 节会讲怎么把它和数据库配置分开管理避免混在一起。2. 接入前的准备Mongoose 安装、连接配置与 TaoToken 统一 Key 管理2.1 安装依赖与目录结构先建项目、装依赖。Mongoose 是独立包不需要额外装 MongoDB 驱动它内部依赖了。mkdir node-mongo-demo cd node-mongo-demo npm init -y npm install mongoose目录我习惯这样分后面 CRUD 封装会用到node-mongo-demo/ ├── config/ │ └── db.js # 数据库连接 ├── models/ │ └── user.js # Schema 与模型 ├── services/ │ └── userService.js # 增删查改封装 └── app.js # 入口2.2 连接 MongoDB 的正确写法新建config/db.js。注意协议名是mongodb端口默认27017端口后面跟的是具体数据库名这里连的是test库。const mongoose require(mongoose); const dbURL mongodb://localhost:27017/test; async function connectDB() { try { await mongoose.connect(dbURL, { useNewUrlParser: true, useUnifiedTopology: true, }); console.log(MongoDB connected); } catch (err) { console.error(connect failed..., err); process.exit(1); } } module.exports connectDB;这里有两个配置项必须说清楚。useNewUrlParser: true是启用新版 URL 解析器老解析器有安全问题useUnifiedTopology: true是启用统一拓扑结构老结构在连接池管理上有效率问题。不加这两个控制台会一直弹弃用警告新版驱动里它们已经默认开启但显式写上兼容性更好。连接是异步操作所以用async/await包起来。如果你要在连接成功后再执行数据库操作要么await connectDB()要么把逻辑放进.then()里别在connect后面直接写查询那时候连接还没建立。2.3 用 TaoToken 统一管理调用凭证数据库连接串里如果带账号密码属于敏感信息不该硬编码。项目里如果还有大模型调用、内容审核这类外部 APIKey 会越来越多。我的做法是分两层数据库配置走.env外部 API 凭证走 TaoToken 统一通道。TaoToken 的 API 地址是 https://taotoken.net/api 它把调用凭证集中管理你不需要在每个项目里散落不同的 Key。具体操作是登录后在控制台创建 API Key然后在代码里通过环境变量引用。这样数据库的MONGO_URI和外部服务的TAOTOKEN_API_KEY各管各的互不干扰。# .env MONGO_URImongodb://localhost:27017/test TAOTOKEN_API_KEYyour_key_here// config/db.js 改造后 const dbURL process.env.MONGO_URI || mongodb://localhost:27017/test;这样切换环境时只改.env代码不用动。凭证管理这块理清楚之后下面进入 Schema 校验。3. 可复制的 Schema 校验配置必填、唯一、默认值与类型约束3.1 三个核心对象的关系在写 CRUD 之前必须搞懂三个对象很多接口都挂在它们身上。打个比方数据库是一栋别墅进别墅的人要登记。Schema是规则制定者你用它声明字段长什么样model是保安拿着规则去拦截数据document是真正进来的人也就是一条条记录。const mongoose require(mongoose); const Schema mongoose.Schema; const userSchema new Schema({ name: { type: String, required: true, }, id_num: { type: Number, required: true, unique: true, }, sex: { type: String, required: true, }, hobby: [String], info: Schema.Types.Mixed, createdAt: { type: Date, default: Date.now, }, }); const UserModel mongoose.model(User, userSchema); module.exports UserModel;3.2 校验规则逐条说明required: true表示必填不传会直接报ValidationError。unique: true表示该字段在集合内唯一注意它是在数据库层建索引实现的不是应用层校验所以重复插入时抛的是MongoServerError而不是校验错误。type支持String、Number、Boolean、Date、Array、Schema.Types.Mixed等Mixed表示任意类型都放行。default: Date.now是默认值不传时自动填当前时间。数组写法[String]表示数组里只能放字符串。3.3 进阶校验枚举、长度与自定义校验器实际项目里光有必填不够比如性别只能填 male/female名字长度要限制。可以这样写const userSchema new Schema({ name: { type: String, required: [true, 名字不能为空], minlength: [2, 名字至少2个字符], maxlength: [20, 名字最多20个字符], }, sex: { type: String, required: true, enum: { values: [male, female], message: 性别只能是 male 或 female, }, }, age: { type: Number, validate: { validator: (v) v 0 v 150, message: 年龄必须在 0 到 150 之间, }, }, });required后面跟数组时第二个元素是自定义错误信息比默认的英文报错友好得多。enum限制取值范围validate可以写任意校验函数。这些规则在create、save、update时都会触发前提是更新时带上runValidators: true这点后面会讲。4. 增删查改全流程验证从 create 到 deleteMany 的实测结果4.1 增create 与 savecreate是最常用的写入方法接收插入对象和回调回调第一个参数是错误对象第二个是成功写入的数据。const UserModel require(./models/user); async function addUser() { try { const data await UserModel.create({ name: Arui, id_num: 10086011, sex: male, hobby: [乒乓球, 网络游戏], info: { remarks: Nothing }, }); console.log(插入成功:, data); } catch (err) { console.error(插入失败:, err.message); } }实测下来如果name不传会直接抛User validation failed: name: 名字不能为空数据不会写进库。如果id_num重复抛的是E11000 duplicate key error这是唯一索引拦截的。4.2 查find、findOne 与条件查询find返回数组就算只有一条也是数组查不到返回空数组。findOne返回单条对象查不到返回null。async function queryUser() { const list await UserModel.find({ sex: male }); console.log(列表:, list); const one await UserModel.findOne({ name: Arui }); console.log(单条:, one); const byId await UserModel.findById(64f...); console.log(按ID:, byId); }常用查询操作符$gt大于、$lt小于、$in在数组内、$regex正则匹配。比如查年龄大于 18 的UserModel.find({ age: { $gt: 18 } })。4.3 改updateOne 与 updateManyasync function updateUser() { const res await UserModel.updateOne( { name: Arui }, { $set: { sex: female } }, { runValidators: true } ); console.log(修改结果:, res); }updateOne只改匹配到的第一条updateMany改所有匹配的。第三个参数runValidators: true很关键不加的话 Schema 里的校验规则不会在更新时生效。返回结果里matchedCount是匹配数modifiedCount是实际修改数。注意别用update方法它已经废弃而且匹配到多条时也只改一条容易出问题。4.4 删deleteOne 与 deleteManyasync function deleteUser() { const res await UserModel.deleteOne({ name: Arui }); console.log(删除结果:, res); const res2 await UserModel.deleteMany({ sex: male }); console.log(批量删除:, res2); }这里有个坑没有delete方法只有deleteOne和deleteMany。返回结果里deletedCount是删除条数。4.5 完整验证脚本把上面串起来app.js里这样跑const connectDB require(./config/db); const UserModel require(./models/user); (async () { await connectDB(); await UserModel.create({ name: Arui, id_num: 10086011, sex: male }); const list await UserModel.find({}); console.log(当前数据:, list); await UserModel.updateOne({ name: Arui }, { $set: { sex: female } }, { runValidators: true }); await UserModel.deleteOne({ name: Arui }); console.log(流程结束); process.exit(0); })();跑完控制台会依次打印连接成功、插入数据、查询列表、修改、删除整条链路验证通过。5. 常见报错排查401、local proxy failed、reading choices 与 OAuth 对照5.1 Mongoose 连接类报错MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017说明 MongoDB 服务没启动或者端口不对。先确认服务在跑brew services list或systemctl status mongod。MongoParseError: Invalid scheme一般是连接串协议名写错了必须是mongodb://开头别写成http://。DeprecationWarning: useNewUrlParser就是没加那两个配置项按第 2.2 节补上即可。5.2 校验类报错ValidationError: name: 名字不能为空是必填校验拦截检查请求体里字段有没有传。CastError: Cast to Number failed for value abc是类型不匹配id_num声明了 Number 却传了字符串。E11000 duplicate key error collection是唯一索引冲突说明id_num重复了。处理方式是捕获这个错误码 11000返回友好提示。5.3 外部调用类报错对照如果项目里同时调了外部 API可能会遇到这几类报错和数据库报错区分开报错信息含义排查方向401 Unauthorized凭证无效或过期检查 API Key 是否正确、是否过期local proxy failed本地网络层拦截检查本机网络配置确认请求能正常出站reading choices响应结构解析失败检查返回体格式确认字段路径OAuth token expired授权令牌过期重新走授权流程刷新令牌这几类报错和 Mongoose 无关但经常在同一个项目里混着出现排查时先看报错来源是数据库层还是网络层。凭证统一管理之后401 这类问题定位会快很多因为只需要检查一个地方。5.4 更新不生效updateOne改了但数据没变八成是没加runValidators: true或者更新对象没包$set。直接写{ sex: female }在新版里会报错必须用{ $set: { sex: female } }。6. 凭证与接口统一管理把 TaoToken 接进你的 Node 项目数据库这条链路跑通之后项目里往往还要接大模型做辅助功能比如自动生成用户标签、内容摘要。这时候 Key 管理就成了新问题。我的做法是把这类调用统一走 TaoTokenAPI 地址 https://taotoken.net/api 在控制台创建 Key 后通过环境变量注入。// services/aiService.js const API_BASE https://taotoken.net/api; const API_KEY process.env.TAOTOKEN_API_KEY; async function generateTag(content) { const res await fetch(${API_BASE}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${API_KEY}, }, body: JSON.stringify({ model: your-model-id, messages: [{ role: user, content: 给这段内容打标签${content} }], }), }); return res.json(); }这样数据库的MONGO_URI和外部服务的TAOTOKEN_API_KEY分开管理切换环境只改.env。如果你还在纠结模型选型可以先去模型对话页面试试效果长期做编码和 Agent 的话Coding Plan 更划算Key 的创建和管理在 API Keys 页面接入细节看文档。把凭证这层理清楚后面加功能就不用到处翻 Key 了。
阅读完成 · 觉得有帮助?
咨询建站