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

使用mgo操作MongoDB执行Upsert时遇到_id字段不可修改报错问题

问题解决方案

报错根本原因

MongoDB 中 _id 是文档的不可变字段,更新场景下不允许修改。你最初的代码里 $set 操作包含了带 ID 字段(对应MongoDB的_id),更新时会尝试修改已有文档的_id,直接触发约束报错。你之前使用$setOnInsert尝试失败的原因是entry结构体仍然携带了ID字段,$set还是会将该字段纳入更新范围,依然会触碰_id的修改约束。

两种可直接落地的解决方法

方案1:手动拆分字段,仅插入场景赋值_id

构造$set内容时主动剔除ID字段,仅将_id放在$setOnInsert中赋值,仅插入时生效,更新时不操作_id,适合需要手动指定_id的场景可以用这个方案:

entry := models.Example{
    UserID:    userID,
    SessionID: sessionID,
    Created:   created,
}
// 构造更新字段映射,不要包含ID/_id
setMap := bson.M{
    "user_id":    entry.UserID,
    "session_id": entry.SessionID,
    "created":    entry.Created,
    // 其他需要更新的字段逐一添加即可
}
query := bson.M{
    "$setOnInsert": bson.M{
        "_id": bson.NewObjectId(),
    },
    "$set": setMap,
}
_, err = mongo.C(mongodb.ExampleCollection).Upsert(bson.M{
    "user_id":    userID,
    "session_id": sessionID,
}, query)

方案2:修改结构体tag,利用mgo自动生成_id

给models.Example的ID字段添加omitempty标签,业务代码中不需要手动赋值ID,插入时mgo会自动生成合法的_id,更新时因为entry没有ID字段,不会触发修改_id的错误,无特殊需求推荐优先使用这个方案:

// 结构体定义修改tag
type Example struct {
    ID        bson.ObjectId `bson:"_id,omitempty"`
    UserID    string        `bson:"user_id"`
    SessionID string        `bson:"session_id"`
    Created   time.Time     `bson:"created"`
}

// 业务代码构造entry时不需要给ID赋值
entry := models.Example{
    UserID:    userID,
    SessionID: sessionID,
    Created:   created,
}
query := bson.M{
    "$set": entry,
}
_, err = mongo.C(mongodb.ExampleCollection).Upsert(bson.M{
    "user_id":    userID,
    "session_id": sessionID,
}, query)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:09:02