在Egg中使用MongoDB及Mongoose:从连接配置到数据模型落地
1. Egg 项目接入 MongoDB 与 Mongoose 的完整链路从连接配置到数据模型落地在 Node.js 后端选型里Egg.js 一直是个很稳的框架它把约定优于配置这件事做得比较彻底目录结构、插件机制、多环境配置都有固定套路。而 MongoDB 作为文档型数据库配合 Mongoose 这个 ODM能让你用接近写对象的方式去操作数据。把这两者接起来Egg 官方生态里有个插件叫 egg-mongoose专门干这件事。这篇要聊的就是这条链路怎么跑通插件怎么装、config.default.js 里连接参数怎么写、plugin.js 怎么声明、Schema 怎么定义、Model 怎么挂载到 app 和 ctx 上最后怎么用接口验证读写真的成功了。适合刚接触 Egg 或者第一次在 Egg 里接 MongoDB 的同学也适合之前用过但配置老是报错、想系统梳理一遍的人。我会把单库和多库两种配置都写出来再给一个带索引、时间戳、虚拟值的 User 模型示例最后附上启动日志和 curl 验证动作你照着敲基本能跑通。先说清楚一个概念Mongoose 里的 Schema 是数据结构的描述Model 是由 Schema 编译出来的构造函数真正对数据库做增删改查的是 Model。Egg 的 egg-mongoose 插件做的事就是把 Mongoose 实例挂到 app 上让你在 model 目录里直接app.mongoose拿到它同时把 model 目录下的文件自动加载成app.model.xxx和ctx.model.xxx。理解这一点后面配置就不容易晕。2. TaoToken 前置准备模型接入与 API Key 获取在正式写 Egg 配置之前先把模型调用这一层准备好。如果你项目里除了数据库读写还要接大模型做对话、代码补全或者 Agent 编排TaoToken 可以作为统一的模型接入入口。它提供 OpenAI 兼容的接口形式Base URL 和 Key 拿到之后在 Egg 里用 axios 或者 openai 的 SDK 都能直接调。第一步是注册并登录控制台。打开 https://taotoken.net/api 这个 API 入口或者从官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 进控制台。登录之后进 API Keys 页面新建一个 Key复制出来存到环境变量里别硬编码进代码。第二步是确认你要用的模型 ID。在模型对话页面可以先试跑一下确认这个模型 ID 是可用的再写进项目配置。模型对话地址是 https://taotoken.net/api/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 在这里发一条消息能正常返回就说明 Key 和模型都对。第三步如果你是要做长期编码或者 Agent 类的任务可以看下 Coding Plan地址是 https://taotoken.net/api/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。它更适合持续性的编码场景比单次调用划算。在 Egg 项目里我一般把 Key 放在config/config.default.js里通过环境变量读取比如process.env.TAOTOKEN_API_KEY然后在 service 层封装一个请求方法。这样本地开发用.env线上用容器环境变量不会把 Key 提交到仓库。接入文档在 https://taotoken.net/api/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的请求格式和参数说明写 service 之前扫一眼能省不少调试时间。这里要提醒一句TaoToken 是模型接入层不是数据库别把它和 MongoDB 的连接配置混在一起。数据库连接走 egg-mongoose模型调用走 HTTP 请求两者在 Egg 里是分开的插件和 service职责清晰。3. 可复制配置plugin.js 声明与 config.default.js 连接参数这一节是核心配置写对了后面基本不会卡。先装依赖在项目根目录执行npm install egg-mongoose --save然后在config/plugin.js里声明插件// config/plugin.js exports.mongoose { enable: true, package: egg-mongoose, };接着是config/config.default.js单数据库连接这样写// config/config.default.js exports.mongoose { url: process.env.MONGODB_URL || mongodb://127.0.0.1:27017/laurel, options: { useNewUrlParser: true, useUnifiedTopology: true, }, };如果你要连多个数据库就换成 clients 形式// config/config.default.js exports.mongoose { clients: { db1: { url: process.env.MONGODB_URL_DB1 || mongodb://127.0.0.1:27017/db1, options: {}, }, db2: { url: process.env.MONGODB_URL_DB2 || mongodb://127.0.0.1:27017/db2, options: {}, }, }, };多库模式下model 里必须通过app.mongooseDB.get(db1)指定用哪个连接否则会报找不到连接。单库模式则直接用app.mongoose就行。这里有个容易踩的坑options里的useNewUrlParser和useUnifiedTopology在新版 Mongoose 里已经默认开启写了也不报错但如果你用的 Mongoose 版本较老不写这两个会有警告。实测下来保持写上比较省心。另外连接字符串里的数据库名laurel要和你在 MongoDB 里实际建的库对应不然 Mongoose 会自动建一个空库你查数据时发现是空的会以为配置没生效。建议先在 MongoDB 里手动建好库和集合或者至少确认连接后show dbs能看到。配置写完后Egg 启动时会自动加载插件并建立连接。你可以在app.js里加一段启动日志确认// app.js module.exports app { app.beforeStart(async () { app.logger.info(MongoDB 连接初始化完成); }); };4. 数据模型落地Schema 定义、虚拟值与 Model 挂载配置通了之后写 model。Egg 约定 model 文件放在app/model/目录下文件名就是 model 名。先看一个单库模式下的 User 模型// app/model/user.js module.exports app { const mongoose app.mongoose; const Schema mongoose.Schema; const UserSchema new Schema( { name: { type: String, required: true }, account: { type: String, unique: true }, password: { type: String }, comments: [{ body: String, date: Date }], tags: { type: [String], index: true }, meta: { votes: Number, favs: Number, }, home: { type: String, alias: h }, }, { timestamps: { createdAt: createdAt, updatedAt: updatedAt }, } ); UserSchema.virtual(fullName) .get(function () { return ${this.name} (${this.account}); }); return mongoose.model(User, UserSchema); };多库模式下model 要改成从指定连接取// app/model/user.js module.exports app { const mongoose app.mongoose; const Schema mongoose.Schema; const conn app.mongooseDB.get(db1); const UserSchema new Schema({ name: { type: String }, account: { type: String, unique: true }, password: { type: String }, }); return conn.model(User, UserSchema); };几个关键点解释一下。timestamps会自动生成createdAt和updatedAt省得自己写时间字段。alias: h是给字段起别名查询时用h和home都能命中。virtual定义的fullName不会存进数据库只在读取时拼接返回注意用toJSON({ virtuals: true })才能带出来。Mongoose 默认会把 model 名转成复数作为集合名User会变成users。如果你不想这样在model()第三个参数手动指定集合名return mongoose.model(User, UserSchema, user);这样集合名就是user不会加 s。这个细节在对接已有数据库时特别重要不然你会发现在新集合里查不到老数据。模型挂载后在 controller 或 service 里通过ctx.model.User访问在 app 层通过app.model.User访问。Egg 会自动把app/model下的文件加载成 model不需要手动 require。5. 验证请求与常见报错排查配置和模型都写好后启动项目npm run dev正常的话控制台会打印 MongoDB 连接成功和 beforeStart 的日志。如果报MongooseError: connect ECONNREFUSED 127.0.0.1:27017说明 MongoDB 服务没起来先确认本地 MongoDB 在跑或者连接字符串的地址端口对不对。写个简单的 controller 验证读写// app/controller/user.js const Controller require(egg).Controller; class UserController extends Controller { async create() { const { ctx } this; const user await ctx.model.User.create({ name: 测试用户, account: test001, password: 123456, }); ctx.body { code: 0, data: user }; } async list() { const { ctx } this; const users await ctx.model.User.find({}); ctx.body { code: 0, data: users }; } }配好路由后用 curl 验证curl -X POST http://127.0.0.1:7001/user/create curl http://127.0.0.1:7001/user/list能返回数据就说明链路通了。下面列几个我实际遇到过的报错和排查方向。Unknown modifier: $pushAll这个报错通常出现在老版本 Mongoose 配合新版 MongoDB 时Schema 选项里加usePushEach: true能绕过但更推荐升级 Mongoose 版本。MongooseError: Operation users.findOne() buffering timed out after 10000ms这个多半是连接没建立成功或者连接字符串指向的库不对。检查config.default.js里的 url以及 MongoDB 是否允许该地址连接。Cannot read property model of undefined一般是 model 文件里app.mongoose拿不到说明插件没启用或者 plugin.js 写错了。确认config/plugin.js里exports.mongoose的 enable 是 true。E11000 duplicate key error这是唯一索引冲突比如 account 字段设了 unique重复插入相同值就会报。要么改值要么在业务层先查再插。如果你在项目里同时用了 TaoToken 做模型调用报401 Unauthorized一般是 Key 没带对或者过期了去 API Keys 页面重新生成一个。报local proxy failed这种检查你的请求地址是不是写成了https://taotoken.net/api而不是带具体路径的接口地址。模型返回里如果出现reading choices相关错误说明响应结构和你解析的字段对不上去接入文档确认一下返回格式。6. 语义一致 CTA把模型能力和数据层串起来数据库这层跑通之后你的 Egg 项目就有了持久化能力。接下来如果要做智能问答、内容生成或者代码辅助可以把 TaoToken 的模型调用封装成一个 service在 controller 里先查 MongoDB 拿上下文再调模型生成结果最后写回数据库。这样数据层和模型层就串起来了。需要 Key 和接入细节的去 API Keys 页面 https://taotoken.net/api/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 拿接入文档在 https://taotoken.net/api/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。想先试模型效果的去模型对话 https://taotoken.net/api/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 发几条消息看看返回。长期做编码和 Agent 的Coding Plan 在 https://taotoken.net/api/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。最后说个实用技巧Egg 的 model 目录支持热加载改完 Schema 重启 dev 就行但如果你改了集合名或者索引记得去 MongoDB 里确认索引有没有真正建上db.users.getIndexes()看一眼别等线上查询慢了才发现索引没生效。

相关新闻

水果采摘机械手结构设计:从力学模型到样机避坑指南

水果采摘机械手结构设计:从力学模型到样机避坑指南

简介:这份毕业设计范文面向机械工程、农业装备及自动化相关专业的本科生与指导教师,围绕水果采摘机械手的结构设计展开,可帮助读者快速理解从需求分析到三维建模的完整设计流程。压缩包内仅含1个docx文档,约2.52MB,内容…

2026/10/17 5:28:25 阅读更多 →
MCP是什么?从零创建一个MCP服务并接入TaoToken的完整实践

MCP是什么?从零创建一个MCP服务并接入TaoToken的完整实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 5:28:25 阅读更多 →
Flask+Vue机房预约系统实战:从框架选型到并发冲突处理

Flask+Vue机房预约系统实战:从框架选型到并发冲突处理

某高校计算机学院的机房,以前基本靠一张纸质登记表加微信群接龙来安排使用,实验课、自由上机、社团培训经常撞时间,管理员一天要在好几份表格之间反复核对。后来我帮学院搭了一套“机房预约管理系统”,后端用Python Flask&#xf…

2026/10/17 5:28:25 阅读更多 →

最新新闻

深入浅出Linux网卡驱动:DMA、NAPI与多队列调优

深入浅出Linux网卡驱动:DMA、NAPI与多队列调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 6:04:33 阅读更多 →
glibc2.27堆题沙箱绕过:tcache、ORW和setcontext实战解析

glibc2.27堆题沙箱绕过:tcache、ORW和setcontext实战解析

从glibc 2.27开始,堆题的常规打法变得很机械:tcache几乎没有限制,double free和poisoning基本是“一键操作”。可一旦题目在堆漏洞外面又套了一层seccomp沙箱,整条利用链就得重新想。你辛辛苦苦把__free_hook改成了system&#xf…

2026/10/17 6:04:33 阅读更多 →
基于MP2642GR-Z与TM4C129EKCPDT的电池主动均衡方案设计与实现

基于MP2642GR-Z与TM4C129EKCPDT的电池主动均衡方案设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 6:04:33 阅读更多 →
储能电池均衡方案选型与MP2642GR-Z+STM32实战

储能电池均衡方案选型与MP2642GR-Z+STM32实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 6:04:33 阅读更多 →
Matlab插值算法手写实验全解析:Lagrange、Newton与三次样条

Matlab插值算法手写实验全解析:Lagrange、Newton与三次样条

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 6:04:33 阅读更多 →
三角分解法与高斯迭代法:线性方程组求解的工程实现与排错指南

三角分解法与高斯迭代法:线性方程组求解的工程实现与排错指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 6:03:33 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →