Node.js Express+MongoDB MVC模型添加更新功能后报错排查
错误详情
TypeError: C:\Users\DELL\Desktop\node-com4muz-database-mvc\views\admin\posts-list.ejs:19 17| <ol id="posts-list"> 18| <% for (const post of posts) { %> >> 19| <li><%- include('includes/post-item', { post: post }) %></li> 20| <% } %> 21| </ol> 22| <% } %> C:\Users\DELL\Desktop\node-com4muz-database-mvc\views\admin\includes\post-item.ejs:3 1| <article class="post-item"> 2| <h2><%= post.title %></h2> >> 3| <p class="post-item-author">Rédigé par <%= post.author.name %></p> 4| <p><%= post.summary %></p> 5| <div class="post-actions"> 6| <form action="/blog/<%= post._id %>/delete" method="POST"> Cannot read properties of undefined (reading 'name') at eval ("C:\Users\DELL\Desktop\node-com4muz-database-mvc\views\admin\includes\post-item.ejs":15:38) at post-item (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\ejs\lib\ejs.js:703:17) at include (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\ejs\lib\ejs.js:701:39) at eval ("C:\Users\DELL\Desktop\node-com4muz-database-mvc\views\admin\posts-list.ejs":29:17) at posts-list (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\ejs\lib\ejs.js:703:17) at tryHandleCache (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\ejs\lib\ejs.js:274:36) at View.exports.renderFile [as engine] (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\ejs\lib\ejs.js:491:10) at View.render (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\express\lib\view.js:135:8) at tryRender (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\express\lib\application.js:657:10) at Function.render (C:\Users\DELL\Desktop\node-com4muz-database-mvc\node_modules\express\lib\application.js:609:3) { path: 'C:\\Users\\DELL\\Desktop\\node-com4muz-database-mvc\\views\\admin\\posts-list.ejs' }
问题根源分析
1. Post实例创建时参数顺序完全错误
在修改后的routes/admin/blog.js的POST /blog/:id/edit路由中,创建Post实例的参数传递顺序与构造函数定义不匹配:
// 路由中的错误调用 const post = new Post( enteredTitle, enteredSummary, enteredContent, req.params.id );
而models/post.js中Post类的构造函数参数顺序为:
constructor(title, summary, content, date, author, image, id)
这里把req.params.id传到了**第四个参数(date)**的位置,第七个参数(id)实际为undefined。导致:
this.id无法被赋值(构造函数中仅当第七个参数id存在时才会设置)save()方法会进入新增post的分支(而非更新分支),插入一个缺少author、date等关键字段的新post- 这个新增的post没有
author字段,渲染列表时访问post.author.name就会触发undefined错误
2. Post模型save方法存在多处语法错误
在修改后的models/post.js的save()方法的更新分支中:
- 未定义变量
postId:查询条件使用{ _id: postId },但postId从未声明,应改为this.id - 字段赋值错误:
$set中错误地将title设为this.id(ObjectId类型),实际应为this.title - 更新逻辑不完整:未保留原post的
author、date、imagePath等字段(虽然$set不会删除原有字段,但参数传递错误导致进入新增分支,根本没执行更新)
修复方案
步骤1:修正路由中Post实例的参数传递
在routes/admin/blog.js的POST /blog/:id/edit路由中,按照构造函数顺序传递参数,仅传入需要更新的字段和id,其余参数可设为undefined:
router.post('/blog/:id/edit', async function (req, res) { const enteredTitle = req.body.title; const enteredSummary = req.body.summary; const enteredContent = req.body.content; // 按照构造函数顺序传递参数:title, summary, content, date, author, image, id const post = new Post( enteredTitle, enteredSummary, enteredContent, undefined, // date 保持原字段,无需传递 undefined, // author 保持原字段,无需传递 undefined, // image 保持原字段,无需传递 req.params.id // 第七个参数才是id ); await post.save(); res.redirect('/posts'); });
步骤2:修复Post模型save方法的更新逻辑
在models/post.js中修正save()方法的错误:
async save() { let result; if (this.id) { // 修正查询条件和字段赋值 result = await db .getDb() .collection('posts') .updateOne( { _id: this.id }, // 使用实例的this.id而非未定义的postId { $set: { title: this.title, // 修正为this.title而非this.id summary: this.summary, content: this.content // 如需更新日期可取消注释:date: new Date() } } ); } else { result = await db.getDb().collection('posts').insertOne({ title: this.title, summary: this.summary, content: this.content, date: this.date, author: this.author, imagePath: this.image }); } return result; }
步骤3:可选优化(确保更新时获取原post完整信息)
如果需要在更新时验证或修改其他字段,建议先从数据库获取原post的完整数据,再覆盖需要更新的内容:
router.post('/blog/:id/edit', async function (req, res) { const postId = new ObjectId(req.params.id); // 获取原post的完整数据 const originalPost = await db.getDb().collection('posts').findOne({ _id: postId }); if (!originalPost) { return res.status(404).render('404'); } const enteredTitle = req.body.title; const enteredSummary = req.body.summary; const enteredContent = req.body.content; // 使用原post的date、author、image字段,仅更新需要修改的内容 const post = new Post( enteredTitle, enteredSummary, enteredContent, originalPost.date, originalPost.author, originalPost.imagePath, req.params.id ); await post.save(); res.redirect('/posts'); });
内容的提问来源于stack exchange,提问作者Sofiane R
相关产品推荐
相关产品推荐

