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

Mongoose按ID删除嵌套数组元素报错404,求排查与解决

问题分析与解决

问题背景

拥有Calendar数据模型,结构包含嵌套的events数组,尝试通过Express路由删除指定日期下的某个事件,但发送DELETE请求返回404,POST请求也无效。

数据模型示例:

{
    "_id": "64ed0c1c706147ee90a1ca00",
    "year": 2023,
    "month": 7,
    "day": 25,
    "events": [
        {
            "title": "return back to the Netherlands",
            "description": "check ID and paper",
            "_id": "64ed0c1c706147ee90a1ca01"
        },
        {
            "title": "finish the exam",
            "description": "celebrating with Hua",
            "_id": "64ed0c1c706147ee90a1ca02"
        }
    ],
    "createdAt": "2023-08-28T21:05:32.928Z",
    "updatedAt": "2023-08-28T21:05:32.928Z",
    "__v": 0
}

路由代码:

router.route('/:year/:month/:day/:eventId').delete(async (req, res) => {
    const year = Number(req.params.year);
    const month = Number(req.params.month);
    const day = Number(req.params.day);
    const eventId = req.params.eventId;

    try {
        const updatedCalendar = await Calendar.findOneAndUpdate(
            { year, month, day },
            { $pull: { events: { _id: eventId } } },
            { new: true }
        );

      if (updatedCalendar) {
          return res.json(updatedCalendar);
      } else {
            return res.status(404).json({ message: 'Date entry not found.' });
        }
    } catch (error) {
          return res.status(500).json({ message: 'Error removing event.', error: error.message });
      }
});

请求地址:http://localhost:3000/Calendar/2023/7/25/64ed0c1c706147ee90a1ca01


问题原因

  1. 路由挂载路径不匹配
    请求路径包含/Calendar前缀,但当前路由的路径是/:year/:month/:day/:eventId,如果这个router没有挂载到/Calendar路径下,Express会找不到对应的路由处理函数,直接返回404。

  2. MongoDB ObjectId类型不匹配
    数据库中events._id是ObjectId类型,但直接用字符串类型的eventId进行匹配,MongoDB无法识别两者相等,导致findOneAndUpdate无法匹配到要更新的文档,返回null,触发代码里的404逻辑。


解决步骤

1. 修正路由挂载路径

确保将该router挂载到/Calendar路径下,在主app文件中添加:

const calendarRouter = require('./path/to/your/calendar/router');
app.use('/Calendar', calendarRouter);

2. 转换EventId为ObjectId类型

在路由代码中,将字符串类型的eventId转换为mongoose的ObjectId,确保匹配数据库中的类型:

const mongoose = require('mongoose'); // 确保已导入mongoose

router.route('/:year/:month/:day/:eventId').delete(async (req, res) => {
    const year = Number(req.params.year);
    const month = Number(req.params.month);
    const day = Number(req.params.day);
    // 转换为ObjectId
    const eventId = new mongoose.Types.ObjectId(req.params.eventId);

    try {
        // 先查询原文档,用于判断事件是否存在
        const originalCalendar = await Calendar.findOne({ year, month, day });
        if (!originalCalendar) {
            return res.status(404).json({ message: 'Date entry not found.' });
        }

        const updatedCalendar = await Calendar.findOneAndUpdate(
            { year, month, day },
            { $pull: { events: { _id: eventId } } },
            { new: true }
        );

        // 检查事件是否被成功移除
        const eventRemoved = originalCalendar.events.length > updatedCalendar.events.length;
        if (eventRemoved) {
            return res.json(updatedCalendar);
        } else {
            return res.status(404).json({ message: 'Event not found for the specified date.' });
        }
    } catch (error) {
        return res.status(500).json({ message: 'Error removing event.', error: error.message });
    }
});

额外优化

  • 增加事件存在性校验:原代码只判断日期是否存在,无法区分“日期存在但事件不存在”的情况,新增逻辑可以更精准地返回错误信息。
  • 参数合法性校验:对year/month/day转换为数字后,可增加范围校验(比如月份在1-12之间),避免无效参数查询。

内容的提问来源于stack exchange,提问作者Slippers

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 05:53:27