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

NodeJS更新MongoDB文档报错:无法修改不可变字段_id

NodeJS更新MongoDB时_id字段不可修改的问题解决

问题场景

我尝试用NodeJS更新MongoDB数据,代码如下:

Controller.js

updateProduct: async (req, res) => {
    try {
        const { params: { id } } = req;
        const { body } = req;
        if (!body || Object.keys(body).length === 0) {
            Response.ERROR(res, new createError.BadRequest());
        } else {
        let product = await ProductsService.updateP(id, body);
    }
        if (!product) {
            Response.ERROR(res, new createError.NotFound());
        } else {
            Response.SUCCSESS(res, 201, `Producto actualizado`, product);
        }
    } catch (error) {
        debug(error);
        Response.ERROR(res);
    }
},

Services.js

const updateP = async (id, product) => {
    const collection = await Database(COLLECTION);
    return collection.updateOne({_id: new ObjectId(id)}, { $set: { ...product } })
};

数据库原始数据:

{
    "_id": "651cd5d91e3c20bda7cea881",
    "name": "shoes",
    "price": 359,
    "quantity": 10
}

请求的body包含_id字段,执行更新时触发错误:

MongoServerError: Performing an update on the path '_id' would modify the immutable field '_id'

期望更新后的数据:

{
    "_id": "651cd5d91e3c20bda7cea881",
    "name": "Coca-cola",
    "price": 359,
    "quantity": 10
}

错误原因

MongoDB的_id是文档的唯一标识,属于不可变字段,无法通过$set操作修改。当前代码直接把包含_id的请求body展开到$set中,因此触发报错。

另外,Controller代码存在作用域问题:let product在else块内声明,外部的if (!product)会访问到未定义的变量,导致即使更新成功,也会返回NotFound错误。

解决方案

  1. 剔除请求body中的_id字段:更新前移除传入对象里的_id,避免尝试修改不可变字段。
  2. 修正Controller变量作用域:将product变量声明移到else块外部,确保后续判断能正确访问更新结果。
  3. 改用findOneAndUpdate:直接返回更新后的文档,无需额外查询,同时方便前端获取最新数据。

修改后的代码示例

修正后的Services.js

const { ObjectId } = require('mongodb');

const updateP = async (id, product) => {
    const collection = await Database(COLLECTION);
    // 解构剔除_id,生成仅含可更新字段的对象
    const { _id, ...updateData } = product;
    // 执行更新并返回修改后的文档
    return collection.findOneAndUpdate(
        { _id: new ObjectId(id) },
        { $set: updateData },
        { returnDocument: 'after' }
    );
};

修正后的Controller.js

updateProduct: async (req, res) => {
    try {
        const { params: { id } } = req;
        const { body } = req;
        let product; // 移至外部声明,确保作用域覆盖后续判断
        if (!body || Object.keys(body).length === 0) {
            Response.ERROR(res, new createError.BadRequest());
        } else {
            product = await ProductsService.updateP(id, body);
        }
        // 判断更新后的文档是否存在
        if (!product?.value) {
            Response.ERROR(res, new createError.NotFound());
        } else {
            Response.SUCCSESS(res, 201, `Producto actualizado`, product.value);
        }
    } catch (error) {
        debug(error);
        Response.ERROR(res);
    }
},

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 00:12:53