1. 从一次用户列表翻车说起mongoDB 增删改查到底难在哪如果你正在搜 mongoDB 增删改查案例大概率不是想背 API而是想跑通一条完整链路本地起服务、连上数据库、把用户信息查出来渲染成页面再顺手把新增、删除、修改都接上。我当初也是这么想的结果第一步就卡住了——MongooseServerSelectionError: connect ECONNREFUSED ::1:27017服务明明开着代码就是连不上。这个案例适合谁适合刚学完 Node.js 基础、想用一个真实小项目把 Express Mongoose mongoDB 串起来的人。它不涉及复杂架构核心就是一张用户表姓名、年龄、爱好、邮箱、密码围绕这张表做四件事——查列表、加用户、删用户、改用户。听起来简单但真正动手时连接字符串写 localhost 还是 127.0.0.1、年龄字段为什么必须转成数字、爱好数组怎么在表单和数据库之间来回转换每个点都能让你停半小时。这篇我会按实际搭建顺序走先给一份可复制的配置骨架config.toml 和 settings.json再逐步实现 CRUD最后把验证动作和常见报错一次讲清。你跟着敲完应该能拿到一个能在浏览器里点点点、数据库里真增真删的完整 demo。中间涉及模型调用或代码补全时我会顺带说下怎么用 TaoToken 的配置骨架接进去让这套项目结构能直接复用到更复杂的场景。2. 前置准备项目骨架与 TaoToken 配置骨架2.1 初始化项目与依赖先建目录、初始化 npm把 mongoose 和 express 装上。这一步没什么坑命令贴出来直接跑mkdir mongodb-user-demo cd mongodb-user-demo npm init -y npm install mongoose express body-parser装完后package.json的 dependencies 里应该能看到mongoose和express。如果你用的是 Node.js 18 及以上版本记住后面连接数据库时优先写127.0.0.1原因在排障章节细说。2.2 可复制的 config.toml 骨架项目根目录建一个config.toml把数据库地址、端口、集合名这些容易变的东西抽出来避免散落在代码里# config.toml [server] port 3000 host 127.0.0.1 [database] uri mongodb://127.0.0.1:27017/playground db_name playground collection users [app] page_size 20这里uri用的是127.0.0.1而不是localhost是踩过坑之后的固定写法。playground是数据库名mongoDB 发现不存在会自动创建不用你手动建库。2.3 settings.json 骨架与 TaoToken 接入位再建一个settings.json放运行时开关和外部服务配置。如果你打算在这个项目里接模型能力比如自动生成用户简介、批量补全测试数据可以把 TaoToken 的配置预留在这里{ app: { name: mongodb-user-demo, debug: true, logLevel: info }, taotoken: { baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY, defaultModel: claude-sonnet, timeoutMs: 30000 } }apiKeyEnv指向环境变量名不要把 key 明文写进文件。真正要用的时候去 TaoToken 控制台生成 API Key然后export TAOTOKEN_API_KEY你的key这样配置骨架就搭好了后面写业务代码时只读配置、不硬编码。想先拿到 key 的话可以从 TaoToken API Keys 页面 进去创建接入细节看 接入文档 就行。3. 可复制配置连接数据库与定义用户集合3.1 数据库连接模块建model/index.js专门负责连接入口文件只 require 一次// model/index.js const mongoose require(mongoose) mongoose.connect(mongodb://127.0.0.1:27017/playground) .then(() console.log(数据库连接成功)) .catch(err console.log(数据库连接失败, err))连接成功会打印「数据库连接成功」。如果这里报ECONNREFUSED先别改代码去看第 5 节的排障。3.2 用户集合规则建model/user.js定义 Schema 并导出模型。注意年龄限制 18 到 80这是后面修改数据时必须转数字的原因// model/user.js const mongoose require(mongoose) const UserSchema new mongoose.Schema({ name: { type: String, required: true, minlength: 2, maxlength: 20 }, age: { type: Number, min: 18, max: 80 }, password: String, email: String, hobbies: [String] }) const User mongoose.model(User, UserSchema) module.exports User3.3 入口文件与路由挂载app.js把数据库连接、列表路由、增删改路由都挂上// app.js const express require(express) const app express() const list require(./router/list) const add require(./router/add) const remove require(./router/remove) const modify require(./router/modify) require(./model/index) app.use(/list, list) app.use(/add, add) app.use(/remove, remove) app.use(/modify, modify) app.listen(3000, () console.log(server started on 3000))到这里骨架就完整了接下来逐个填 CRUD。4. 增删改查逐步实现与验证4.1 查列表页渲染所有用户router/list.js里用User.find()拿全部数据拼成 HTML 表格。爱好是数组渲染时循环输出// router/list.js const express require(express) const list express.Router() const User require(../model/user) list.get(/, async (req, res) { const users await User.find() let html table classtabletrtd用户名/tdtd年龄/tdtd爱好/tdtd邮箱/tdtd操作/td/tr users.forEach(item { html trtd${item.name}/tdtd${item.age}/tdtd item.hobbies.forEach(h { html span${h} /span }) html /tdtd${item.email}/td tda href/remove?id${item._id}删除/a a href/modify?id${item._id}修改/a/td/tr }) html /table res.send(html) }) module.exports list启动node app.js浏览器打开http://127.0.0.1:3000/list能看到用户表格就说明查询通了。4.2 增表单提交写入数据库router/add.js用 body-parser 解析表单爱好字段按|分割成数组再入库// router/add.js const express require(express) const bodyParser require(body-parser) const add express.Router() const User require(../model/user) add.use(bodyParser.urlencoded({ extended: false })) add.post(/, async (req, res) { const hobbies req.body.hobbies.split(|) await User.create({ name: req.body.name, age: req.body.age, email: req.body.email, hobbies: hobbies, password: req.body.password }) res.redirect(/list) }) module.exports add表单里爱好输入「足球|篮球」提交后数据库里就是[足球,篮球]。4.3 删按 id 删除单条router/remove.js用findOneAndDelete根据 query 里的 id 删除// router/remove.js const express require(express) const remove express.Router() const User require(../model/user) remove.get(/, (req, res) { User.findOneAndDelete({ _id: req.query.id }).then(result { console.log(已删除:, result) res.redirect(/list) }) }) module.exports remove点列表里的删除链接页面刷新后该用户消失控制台打印被删文档。4.4 改先查后替换修改分两步GET 拿 id 查出数据填进表单POST 用findOneAndReplace替换。注意年龄要parseInt爱好要split// router/modify.js const express require(express) const bodyParser require(body-parser) const modify express.Router() const User require(../model/user) modify.use(bodyParser.urlencoded({ extended: false })) modify.get(/, async (req, res) { const user await User.findById(req.query.id) res.send(form action/modify methodpost input typehidden nameid value${req.query.id} 姓名input namename value${user.name} 年龄input nameage value${user.age} 爱好input namehobbies value${user.hobbies.join(|)} 邮箱input nameemail value${user.email} 密码input namepassword value${user.password} button typesubmit提交/button/form) }) modify.post(/, async (req, res) { const hobbies req.body.hobbies.split(|) const age parseInt(req.body.age) await User.findOneAndReplace( { _id: req.body.id }, { name: req.body.name, age, hobbies, email: req.body.email, password: req.body.password }, { returnNewDocument: false } ) res.redirect(/list) }) module.exports modify4.5 验证动作清单跑完上面四步按这个顺序验证一遍动作预期结果访问 /list表格显示所有用户提交新增表单列表多一行数据库多一条点删除链接该行消失控制台打印被删文档点修改、改年龄为 30列表年龄更新数据库同步5. 本篇常见错排查5.1 ECONNREFUSED ::1:27017这是最高频的报错。Node.js 18 及以上会把localhost优先解析成 IPv6 的::1而本地 mongoDB 默认只监听 IPv4。解决办法就是把连接字符串里的localhost换成127.0.0.1mongoose.connect(mongodb://127.0.0.1:27017/playground)报错信息里看到::1:27017而不是127.0.0.1:27017基本就是这个原因。5.2 年龄校验失败Schema 里 age 是 Number 且限制 18 到 80。表单提交上来的是字符串直接存会触发校验错误。修改路由里必须parseInt(req.body.age)新增路由同理。5.3 爱好变成一整个字符串如果忘了split(|)数据库里 hobbies 会存成足球|篮球一个字符串而不是数组。渲染时item.hobbies.forEach就会报错。检查新增和修改两处都要分割。5.4 修改后数据没变findOneAndReplace的 query 用的是req.body.id如果表单里 hidden 的 id 没传对就会匹配不到文档。打开控制台看有没有打印「No document matches」有的话检查 hidden input 的 name 和取值。5.5 路由 404app.use(/add, add)挂载后add 路由内部写add.post(/)才对。如果写成add.post(/add)实际路径会变成/add/add。每个子路由的路径都是相对于挂载点的。6. 把配置骨架用到更复杂的场景这套项目结构跑通之后config.toml 和 settings.json 的价值就体现出来了数据库地址、端口、集合名、外部服务配置全在文件里换环境只改配置不动代码。如果你后面想在这个用户系统上加 AI 能力比如根据用户爱好自动生成标签、批量造测试数据settings.json 里预留的 TaoToken 配置就能直接接上。模型对话类需求可以从 TaoToken 模型对话 进去试如果是长期写代码、跑 Agent 任务Coding Plan 更适合按周期用。接入前记得先去 API Keys 生成 key具体参数和调用方式对照 接入文档 配就行。官网入口在 taotoken.netAPI 地址统一用https://taotoken.net/api。最后留一个我踩过的坑改完 Schema 后如果数据库里已有旧数据字段类型对不上会静默失败最省事的办法是先把集合清空再重新导入测试数据。
企业数字化 ERP 产品动态
相关推荐
5G网优工具合集Zip处理全流程:从校验解压到落地实战 简介:这套合集包含30个实用5G网络优化工具,覆盖同覆盖判断、拉线制作、基站位置计算、天线下倾角与覆盖距离计算、重叠覆盖度分析、共覆盖扇区核查等高频场景,解决网优工作中工具零散、版本杂乱的问题。压缩包共155个文件,大小约1… · 2026/9/26 9:03:46
豆瓣Top250爬虫+数据分析可视化:从requests到pyecharts实战 简介:这是一份面向Python爬虫与数据分析初学者的豆瓣电影综合实战项目。它演示了从网络数据采集、数据库存储、数据清洗与统计分析,到最终可视化展示的完整流程,适合希望系统练手数据技能、准备课程设计或个人作品集的读者。压缩包共14个文件… · 2026/9/26 9:03:46
基于Android Studio的天气预报APP毕业设计实现与避坑指南 简介:面向计算机专业毕业设计与项目实战练习者的Android Studio天气预报APP完整项目,曾获导师指导并以98分高分通过评审,源码均经本地编译与严格调试,确保可运行。资源同时适用于课程设计、期末大作业等场景,难度适中&… · 2026/9/26 9:03:40
Open-Meteo免费天气API:不注册不填Key,5分钟拿到本地今日天气 Open-Meteo免费天气API:不注册不填Key,5分钟拿到本地今日天气 【免费下载链接】open-meteo Free Weather Forecast API for non-commercial use 项目地址: https://gitcode.com/GitHub_Trending/op/open-meteo
明天有户外活动,你只想确… · 2026/9/26 10:12:32
Drawdown 回撤分析配 TaoToken:config.toml 骨架与验证动作 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 10:12:32
Atlas 300V 24G上YOLO模型部署实战:环境配置、转换与推理优化 1. 先搞清楚Atlas 300V 24G到底是什么定位1.1 规格拆解:一张容易被低估的推理卡先说结论:Atlas 300V 24G就是昇腾生态里面向边缘和推理场景的加速卡,核心芯片是昇腾310P,24GB的LPDDR4X显存,整卡功耗72W左右,… · 2026/9/26 10:12:26
Linux PCI驱动开发核心框架与实现要点全解析 2. 整体框架拆解:先画出Linux PCI驱动的“地图”3. 数据结构:PCI设备在内核里的“身份档案”4. 枚举与初始化:从硬件发现到驱动绑定5. 资源管理与地址映射6. 驱动核心操作:probe、remove与file_operations7. 中断处理与DMA8. 调试… · 2026/9/26 10:12:20
2026年CTF夺旗赛新手入门指南:从零到独立解题的完整路径 1. 从零认识CTF夺旗赛:它到底在比什么很多人第一次听到“CTF夺旗赛”这个词,脑子里浮现的是两拨人举着旗子互相冲锋的画面。实际上,CTF(Capture The Flag)是网络安全领域的一种竞技比赛形式,参赛者通过技术… · 2026/9/26 10:12:20
Cursor 配 TaoToken:settings.json 骨架与中文回复设置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 10:12:08
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46