Mongoose嵌套Schema请求数据未存入数据库问题排查
问题:嵌套数组无法通过PATCH请求更新
我无法理解为何请求数据未存入数据库。我使用Mongoose定义了含嵌套对象的Schema,尝试发送请求更新嵌套对象内的特定数组,请求返回成功但数据未添加。以下是相关代码:
Schema
const personSchema = new mongoose.Schema({ connections: { parents: {type : Array}, children: {type : Array} } })
路由
router.patch('/v2/:id', getPerson, async (req, res) => { if (req.body.connections != null) { if (req.body.connections.parents != null) { res.person.connections.parents.push(req.body.connections.parents); } if (req.body.connections.children != null) { res.person.connections.children.push(req.body.connections.children); } } try { const updatePerson = await res.person.save(); res.status(200).json({ message: 'Success' }) } catch (error) { res.status(400).json({ message: error.message }) } })
中间件
async function getPerson(req, res, next) { let person; try { person = await Person.findById(req.params.id); if (person === null) { return res.status(404).json({ message: 'Cannot find the person' }); } } catch (error) { return res.status(500).json({ message: error.message }); } res.person = person; next(); }
请求
PATCH http://localhost:3100/api-db/v2/62e28682cecc9120c7af9de5 Content-Type: application/json { "connections.parents" : "test" }
数据库连接已建立,目标文档已存在。我怀疑是请求格式错误,但未找到嵌套请求相关资料,非嵌套请求可正常执行,请问问题出在哪里?
问题分析与解决方案
1. 请求体格式不匹配
路由代码中判断req.body.connections是否存在,再读取req.body.connections.parents,但当前请求体用了"connections.parents": "test"这种点分隔的扁平键名,Express的JSON解析器不会自动将其解析为嵌套对象,导致req.body.connections为undefined,后续数组push逻辑完全没执行,数据库数据自然无变化。
修正后的请求体:
{ "connections": { "parents": "test" } }
2. 数组push逻辑的潜在问题
即使请求格式正确,当前push逻辑会把传入值整个作为一个元素推入数组:如果传单个值(如"test")结果正常,但如果传数组(如["test1", "test2"]),会得到parents: [["test1", "test2"]]的嵌套数组,不符合预期。
若需支持单个值或批量添加,可修改路由逻辑:
router.patch('/v2/:id', getPerson, async (req, res) => { if (req.body.connections) { // 处理parents:单个值直接push,数组则展开合并 if (req.body.connections.parents != null) { if (Array.isArray(req.body.connections.parents)) { res.person.connections.parents.push(...req.body.connections.parents); } else { res.person.connections.parents.push(req.body.connections.parents); } } // 处理children逻辑同理 if (req.body.connections.children != null) { if (Array.isArray(req.body.connections.children)) { res.person.connections.children.push(...req.body.connections.children); } else { res.person.connections.children.push(req.body.connections.children); } } } try { const updatePerson = await res.person.save(); res.status(200).json({ message: 'Success', data: updatePerson }) } catch (error) { res.status(400).json({ message: error.message }) } })
3. 可选:使用Mongoose原子更新提升效率
当前先查询再修改保存的方式,可替换为Mongoose的$push原子操作,减少数据库交互:
router.patch('/v2/:id', async (req, res) => { const updateOps = {}; if (req.body.connections?.parents != null) { updateOps['connections.parents'] = req.body.connections.parents; } if (req.body.connections?.children != null) { updateOps['connections.children'] = req.body.connections.children; } try { const updatePerson = await Person.findByIdAndUpdate( req.params.id, { $push: updateOps }, // $push自动兼容单个值或数组 { new: true, runValidators: true } // 返回更新后文档,触发Schema验证 ); if (!updatePerson) { return res.status(404).json({ message: 'Cannot find the person' }); } res.status(200).json({ message: 'Success', data: updatePerson }) } catch (error) { res.status(400).json({ message: error.message }) } })
该方式无需getPerson中间件,直接完成查询+更新,效率更高。
内容的提问来源于stack exchange,提问作者Evgeniy Mokrushin
相关产品推荐
相关产品推荐

