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

NodeJS+Mongoose更新用户后,Product模型owner信息首次请求未同步

问题:更新用户信息后,Product模型的owner字段未实时同步更新

我用NodeJS + Mongoose开发,MongoDB里有User和Product两个模型,用户与产品是一对多关联(一个用户拥有多个产品,一个产品对应一个用户)。更新用户信息时,只有User模型成功更新,Product模型中的owner信息还是旧数据;没有报错,但第二次发起请求时,Product模型才会同步更新用户信息。


用户控制器(USER CONTROLLER)

static async ChangeUser(req, res) {
    
    const {name, password, email, location} = req.body

    const changesToDo = {
        name, 
        password,
        email,
        location
    }

    const user = await UserBusiness.GetUserByToken(req)
    if (user.status) {
        res.status(user.status).json({message: user.msg})
    }

    const changedUser = await UserBusiness.ChangesToDo(changesToDo, user)
    if (changedUser.status) {
        res.status(changedUser.status).json({message: changedUser.msg})
    }

    return res.status(200).json({message: "Alterações concluídas", user: changedUser})
}

业务逻辑层(USER BUSINESS)

static async ChangesToDo(changes, user) {

    if (!changes.name || changes.name.trim() == "") {
        changes.name = user.name
    }
    if (await this.UserExists(changes.email)) {
        return new EndMsg(400, "Email já está em uso")
    }
    if (!changes.email || changes.email.trim() == "") {
        changes.email = user.email
    }

    const pwdCompare = await bcrypt.compare(changes.password, user.password)

    if (pwdCompare || !changes.password || changes.password.trim() == "") {
        changes.password = user.password
    } else {
        const salt = bcrypt.genSaltSync(12)
        const hash = bcrypt.hashSync(changes.password, salt)
        changes.password = hash
    }
    if (!changes.location || changes.location.trim() == "") {
        changes.location = user.location
    }

    const updateUser = await UserRepository.UpdateUser(changes, user)
    if (updateUser.status) {
        return new EndMsg(updateUser.status, updateUser.msg)
    }
    return updateUser
}

数据访问层(USER REPOSITORY)

static async UpdateUser(changes, user) {

    try {
        const update = await User.findByIdAndUpdate(user._id, {name: changes.name, password: changes.password, email: changes.email, location: user.location})                      
        if (!update) {
            return new EndMsg(400, "Nao foi possível alterar os dados")
        }

        const otherUpdates = await Product.updateMany({'owner._id': user._id}, {owner: user})

        
        console.log(otherUpdates)
        return update
    } catch(err) {
        console.log(err)
        return new EndMsg(500, err)
    }
}

用户模型(USER MODEL)

const mongoose = require('../db/coon')
const Product = require('../models/Product')

const { Schema } = mongoose

const User = mongoose.model(
    'User',
    new Schema({
        name: {
            type: String,
            required: true,
        },
        password: {
            type: String,
            required: true,
        },
        email: {
            type: String,
            required: true
        },
        wishList: [{
            type: Object
        }],
        location: {
            type: String
        },

        product: Object
    },
    {timestamps: true}
    ),
)

module.exports = User

产品模型(PRODUCT MODEL)

const mongoose = require('../db/coon')

const { Schema } = mongoose

const Product = mongoose.model(
    'Product',
    new Schema({
        description: {
            type: String,
            required: true
        },
        title: {
            type: String,
            required: true
        },
        value: {
            type: Number,
            required: true
        },
        quantity: {
            type: Number,
            required: true
        },
        image: {
            type: String,
        },
        rating: {
            type: Number
        },
        secao: [{
            type: Object
        }],
        owner:{
            type: Object
        }
    })
)

module.exports = Product

问题原因

  1. findByIdAndUpdate默认返回旧数据:Mongoose的findByIdAndUpdate方法默认返回更新前的用户文档,你用这个旧的user对象去更新Product的owner字段,自然不会同步最新的用户信息。
  2. 第二次请求生效的原因:第二次请求时,GetUserByToken会从数据库拉取已更新的用户数据,此时用新数据更新Product,就能同步成功。

解决方案

方案1:修复实时同步问题

修改UserRepository.UpdateUser,给findByIdAndUpdate添加{new: true}选项获取更新后的用户数据,并用它更新Product的owner字段,同时修正location参数错误:

static async UpdateUser(changes, user) {
    try {
        // 添加{new: true}获取更新后的用户数据
        const updatedUser = await User.findByIdAndUpdate(
            user._id, 
            {name: changes.name, password: changes.password, email: changes.email, location: changes.location},
            {new: true}
        )                      
        if (!updatedUser) {
            return new EndMsg(400, "Nao foi possível alterar os dados")
        }

        // 用更新后的用户对象同步Product的owner
        const otherUpdates = await Product.updateMany(
            {'owner._id': user._id}, 
            {owner: updatedUser}
        )

        console.log(otherUpdates)
        return updatedUser
    } catch(err) {
        console.log(err)
        return new EndMsg(500, err)
    }
}

方案2:优化关联设计(推荐)

当前直接嵌入User对象到Product的owner字段会导致数据冗余和同步问题,改用Mongoose引用关联更合理:

  1. 修改Product模型的owner为引用类型:
// PRODUCT MODEL
const Product = mongoose.model(
    'Product',
    new Schema({
        // 其他字段不变
        owner:{
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User',
            required: true
        }
    })
)
  1. 修改User模型添加products引用:
// USER MODEL
const User = mongoose.model(
    'User',
    new Schema({
        // 其他字段不变
        products: [{
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Product'
        }]
    },
    {timestamps: true}
    ),
)
  1. 查询Product时通过populate获取用户信息:
// 示例:查询产品并关联最新用户数据
const products = await Product.find().populate('owner', 'name email location');

这种设计无需手动同步用户数据,修改User后,查询Product时自动获取最新用户信息,同时避免数据冗余。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 07:47:41