Mongoose获取文档ID时article.id返回undefined问题求解
问题根因
代码存在两处核心错误,直接导致id取值为undefined:
- Mongoose的
save()是异步方法,返回值为Promise对象,你没有等待异步操作执行完成,就直接把返回的Promise赋值覆盖了原本创建的article文档实例,后续访问属性时实际是在Promise对象上取值,自然拿不到文档id。 - 路由处理函数未标记为
async,无法使用await等待异步操作,同时未被等待的异步操作抛出的错误,不会进入你写的catch块,会直接触发未捕获异常。
你在Step1位置打印article._id能正常输出,是因为该日志在save赋值操作之前执行,此时article还是刚初始化的Mongoose文档实例——Mongoose新建文档实例时就会默认生成ObjectId类型的_id,不需要等待数据存入数据库。执行完article = article.save()后,原文档实例被Promise覆盖,后续取值自然返回undefined。
补充:正常状态下Mongoose文档实例默认提供id虚拟属性,会返回_id的字符串值,保存完成的实例用article.id完全可以取到正确值,不需要强制改用_id。
修复方案
修改POST路由逻辑,给处理函数加async标记,等待save操作完成后再执行跳转,同时注意不要在保存阶段覆盖原article实例,避免保存失败时catch块无法拿到原表单数据渲染页面:
const express = require('express'); const Article = require('./../models/article') const router = express.Router(); router.get('/new', (req, res) => { res.render('articles/new', { article: new Article() }) }); router.get('/:id', (req, res) => { res.send(req.params.id); }); // 给路由处理函数增加async标记 router.post('/', async (req, res) => { let article = new Article({ title: req.body.title, description: req.body.description, markdown: req.body.markdown }); try { console.log("Try Step 1"); console.log(article._id); // 等待保存完成,用新变量接收保存后的文档实例,不覆盖原article const savedArticle = await article.save() console.log("Try Step 2"); console.log("Try Step 3"); // 用保存完成的实例取id跳转 res.redirect(`/articles/${savedArticle.id}`); } catch (e) { // 打印错误对象方便排查具体报错原因 console.log("Save error: ", e); res.render('articles/new', { article: article }); } }); module.exports = router
原有Schema定义不需要修改,配置完全正常,重启服务即可正常获取id完成跳转。
内容的提问来源于stack exchange,提问作者SKYZE
相关产品推荐
相关产品推荐

