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

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逻辑完全错误:

  1. 更新路径错误:Project模型本身并没有projects字段,你要更新的是Project文档自身的属性(比如name或companyBackground),不需要加projects.$.前缀。
  2. 返回旧文档导致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()方法。

正确的处理方式有两种:

  1. 直接更新Project模型:既然是引用关联,项目数据存在Project集合中,直接更新Project文档即可,不需要修改User的projects数组(因为数组里存的是_id,只要Project文档更新,后续查询User时用populate('projects')就能拿到最新的项目数据)。
  2. 如果非要通过User模型操作(不推荐,多此一举),可以用数组的find方法找到对应的_id,再更新,但实际上没必要,因为项目数据不在User集合里。

关于模型设计的疑问

不需要将项目设为普通数组,你当前的引用式关联设计是合理的,适合项目数据需要被多个用户共享,或者项目数据较大的场景。如果是嵌入式子文档(直接存projectSchema对象在user.projects里),才需要用子文档的操作方式,但引用式关联更符合你现在的需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:51:38