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

Mongoose删除菜单数组元素时出现多类异常问题求助

菜单元素删除相关问题及解决方案

问题背景

原本用updateOne+$pull方式删除菜单元素,存在HTML元素无法移除的问题,改为过滤数组后保存解决了该问题,但删除菜单最后一个元素时仍有错误。以下是遇到的具体问题及对应代码:


问题1:fetch请求成功但无法进入then(),页面需刷新才更新

后端路由代码(PUT方法)

router.put('/menus/:menuid/items/:itemid', async (req, res, next) => {
    console.log('attempting to delete menu item...')
    const menu = await Menu.findById(req.params.menuid)
    const item = menu.items.find(item => item.id === req.params.itemid)
    console.log(item)
    console.log('updating...')
    const response = await Menu.updateOne(
        { _id: menu._id },
        { $pull: { items: { _id: item._id } } }
    )
    console.log(response)
    req.menu = await Menu.findById(req.params.menuid) 
})

前端fetch代码

function redirectThenDeleteElement(path, id, method) {        
        console.log("redirect to " + path + " using " + method)
        fetch(path, { method: method })
            .then(response => {
                if (response.ok) {
                    console.log('fetch successful')
                    const itemToDelete = document.getElementById(id)
                    itemToDelete.remove()
                } else {
                    console.log('error with request')
                }
            }).catch(error => {
                console.error('error with fetch call: \n' + error)
            })
           
}

问题现象:后端能成功删除元素,但前端fetch无法进入then()的response.ok分支,页面元素需手动刷新才消失。


问题2:删除特定场景下的菜单最后一个元素触发重复键错误

问题现象:删除单个菜单的最后一个元素、新增后删除均正常;但删除一个菜单的所有元素后,再删除另一个菜单的最后一个元素时,抛出错误:

MongoServerError: E11000 duplicate key error collection: pfa-site.menus index: items.title_1 dup key: { items.title: null }

即使移除menuItemSchema中title的unique属性,问题依旧。


问题3:updateOne添加回调函数后触发查询重复执行错误

后端路由代码(PATCH方法)

router.patch('/menus/:menuid/items/:itemid', async (req, res, next) => {
    console.log('attempting to delete menu item...')
    const menu = await Menu.findById(req.params.menuid)
    const item = menu.items.find(item => item.id === req.params.itemid)
    console.log(item)
    console.log('updating...')
    const response = await Menu.updateOne(
        { _id: menu._id },
        { $pull: { items: { _id: item._id } } },
        function(error, result) {
            if (error) {
                console.log(error)
            } else {
                console.log(result)
            }
        }
    )
    console.log(response)
    req.menu = await Menu.findById(req.params.menuid)       
})

问题现象:添加回调函数后,删除任何元素都会抛出错误:

MongooseError: Query was already executed: Menu.updateOne({ _id: new ObjectId("63b3737f6d748ace63beef8a... at model.Query._wrappedThunk [as _updateOne]

解决方案

针对问题1:fetch无法进入then()

后端路由未返回响应,导致前端fetch一直处于等待状态。修改路由,操作完成后返回JSON响应:

router.put('/menus/:menuid/items/:itemid', async (req, res, next) => {
    console.log('attempting to delete menu item...')
    const menu = await Menu.findById(req.params.menuid)
    const item = menu.items.find(item => item.id === req.params.itemid)
    console.log(item)
    console.log('updating...')
    const response = await Menu.updateOne(
        { _id: menu._id },
        { $pull: { items: { _id: item._id } } }
    )
    console.log(response)
    const updatedMenu = await Menu.findById(req.params.menuid)
    // 返回成功响应
    res.status(200).json({ success: true, menu: updatedMenu })
})

针对问题2:重复键错误

原因是MongoDB中数组字段的唯一索引会将空数组视为null,多个空数组菜单会触发重复键冲突。需手动删除集合中的对应索引:

  1. 连接MongoDB Shell:
mongo
  1. 切换目标数据库:
use pfa-site
  1. 删除items.title的索引:
db.menus.dropIndex("items.title_1")

同时确保menuItemSchema中title的unique属性设为false,重启服务即可。

针对问题3:updateOne回调与await冲突

Mongoose不允许同时使用await和回调函数,二者二选一即可:

// 方案:只用await+try/catch处理异常
router.patch('/menus/:menuid/items/:itemid', async (req, res, next) => {
    console.log('attempting to delete menu item...')
    const menu = await Menu.findById(req.params.menuid)
    const item = menu.items.find(item => item.id === req.params.itemid)
    console.log(item)
    console.log('updating...')
    try {
        const response = await Menu.updateOne(
            { _id: menu._id },
            { $pull: { items: { _id: item._id } } }
        )
        console.log(response)
        const updatedMenu = await Menu.findById(req.params.menuid)
        res.status(200).json({ success: true, menu: updatedMenu })
    } catch (error) {
        console.log(error)
        res.status(500).json({ success: false, error: error.message })
    }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 11:16:01