Mongoose中更新数组内关联子文档遇问题求助
Mongoose关联模型更新失败排查与解决
模型定义
我在两个文件中定义了两个Mongoose模型:
// models/Projects.js const mongoose = require('mongoose'); export const projectSchema = new mongoose.Schema({ name: { type: String, required: true, trim: true, }, companyBackground: { type: String, required: false, trim: true, } }); module.exports = mongoose.models.Project || mongoose.model('Project', projectSchema);
// models/User.js const mongoose = require('mongoose'); const { projectSchema } = require('./Project'); const userSchema = new mongoose.Schema({ projects: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Project' }] }); module.exports = mongoose.models.User || mongoose.model('User', userSchema);
成功创建关联的代码
我可以通过以下代码创建新用户并关联新项目:
import dbConnect from "utils/dbConnect"; import User from "models/User"; import Project from "models/Project"; export default async (req, res) => { await dbConnect(); const { query: { id }, method } = req; switch (method) { case "POST": try { const user = await User.findById(id); if (!user) { return res.status(400).json({ success: false, message: "User not found" }); } const newProject = new Project(req.body); console.log(newProject); user.projects.push(newProject); await user.save(); if (!user) { return res.status(400).json({ success: false, message: "Project not added" }); } res.status(200).json({ data: user }); } catch (error) { res.status(400).json({ success: false, message: error.message }); } break; default: res.status(400).json({ success: false }); break; } };
更新关联项目时的问题
我尝试更新关联的项目时多次失败,具体情况如下:
问题1:Project.findOneAndUpdate返回null
以下代码执行后返回null:
const updateString = "projects.$." + req.body.property; Project.findOneAndUpdate( { _id: req.body.projectid }, { $set: { [updateString]: req.body.value } }, function (error, success) { if (error) { console.log('error'); console.log(error); } else { console.log("success"); console.log(success); // 返回null } } );
问题2:user.projects.id()不是函数
调用user.projects.id()时提示该方法不存在:
User.findById(userid) .then((user => { const project = user.projects.id(req.body.projectid); // user.projects.id is not a function project.set(newContent); return user.save(); })) .then((user) => { res.send(user); }) .catch((error) => { console.log('error: ', error.message); res.status(400).json({ success: false, message: error.message }); });
我已在MongoDB Atlas中确认项目已成功创建,请问哪里操作出错了?是否应该将项目设为普通数组而非Mongoose对象?
问题分析与解决
针对问题1的错误原因与修复
你的Project.findOneAndUpdate逻辑完全错误:
- 更新路径错误:
Project模型本身并没有projects字段,你要更新的是Project文档自身的属性(比如name或companyBackground),不需要加projects.$.前缀。 - 返回旧文档导致null误解:
findOneAndUpdate默认返回更新前的旧文档,如果该文档之前不存在才会返回null,但你确认项目已创建,所以是路径错误导致更新没匹配到文档,最终返回null。
修复后的代码:
Project.findOneAndUpdate( { _id: req.body.projectid }, { $set: { [req.body.property]: req.body.value } }, { new: true }, // 加上这个选项,返回更新后的新文档 function (error, success) { if (error) { console.log('error:', error); } else { console.log("success:", success); } } );
针对问题2的错误原因与修复
user.projects.id()方法不存在的核心原因是:你定义的user.projects是ObjectId数组,不是嵌入式子文档数组。Mongoose的id()方法只有嵌入式子文档数组才会提供,而你这里用的是引用式关联(存储的是Project的_id),所以这个数组就是普通的ObjectId数组,没有id()方法。
正确的处理方式有两种:
- 直接更新Project模型:既然是引用关联,项目数据存在Project集合中,直接更新Project文档即可,不需要修改User的projects数组(因为数组里存的是_id,只要Project文档更新,后续查询User时用
populate('projects')就能拿到最新的项目数据)。 - 如果非要通过User模型操作(不推荐,多此一举),可以用数组的
find方法找到对应的_id,再更新,但实际上没必要,因为项目数据不在User集合里。
关于模型设计的疑问
不需要将项目设为普通数组,你当前的引用式关联设计是合理的,适合项目数据需要被多个用户共享,或者项目数据较大的场景。如果是嵌入式子文档(直接存projectSchema对象在user.projects里),才需要用子文档的操作方式,但引用式关联更符合你现在的需求。
内容的提问来源于stack exchange,提问作者user2947684
相关产品推荐
相关产品推荐

