You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:27:25