使用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
相关产品推荐
相关产品推荐

