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,多个空数组菜单会触发重复键冲突。需手动删除集合中的对应索引:
- 连接MongoDB Shell:
mongo
- 切换目标数据库:
use pfa-site
- 删除
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
相关产品推荐
相关产品推荐

