Go操作MongoDB:模型与客户端创建及_id自动生成问题排查
MongoDB自动生成_id时出现重复键错误排查与解决
问题描述
定义了如下Go结构体用于MongoDB的TripFeedback数据模型:
type TripFeedback struct { ID primitive.ObjectID `json:"_id" bson:"_id"` UserID string `json:"user_id" bson:"user_id"` WaybillID uint64 `json:"waybill_id" bson:"waybill_id"` Rating Rating `json:"rating" bson:"rating"` Comment string `json:"comment" bson:"comment"` CreatedAt time.Time `json:"created_at" bson:"created_at"` }
期望让MongoDB自动生成_id字段,因此在创建实例时未手动设置ID,执行插入操作:
feedback := model.NewTripFeedback( createRequest.UserID, createRequest.WaybillID, rating, createRequest.Comment, createRequest.ReceivedAt, ) _, err = r.collection.Create(ctx, feedback)
但插入时触发重复键错误:
write errors : [E11000 duplicate key error collection: drive.feedback index: _id_ dup key: { _id: ObjectId('000000000000000000000000') }]"
问题原因
primitive.ObjectID类型在Go中的默认值是全零的ObjectID(即ObjectId('000000000000000000000000')),而非未定义状态。当你向MongoDB插入包含这个全零ID的文档时,MongoDB会将其视为你主动指定的_id值,而不是自动生成新ID。多次插入时,所有文档的_id都会是这个全零值,触发_id字段默认唯一索引的重复键错误。
解决办法
1. 将ID字段改为指针类型(推荐)
修改结构体,把ID字段定义为*primitive.ObjectID,并添加omitempty标签。这样当指针为nil时,序列化时会忽略该字段,MongoDB就会自动生成新的_id:
type TripFeedback struct { ID *primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` UserID string `json:"user_id" bson:"user_id"` WaybillID uint64 `json:"waybill_id" bson:"waybill_id"` Rating Rating `json:"rating" bson:"rating"` Comment string `json:"comment" bson:"comment"` CreatedAt time.Time `json:"created_at" bson:"created_at"` }
同时确保NewTripFeedback构造函数不会给ID字段赋值,让它保持默认的nil状态。
2. 手动构造插入文档(备选方案)
如果不想修改结构体类型,可以在插入时用bson.M手动构造文档,主动排除_id字段。示例如下:
doc := bson.M{ "user_id": createRequest.UserID, "waybill_id": createRequest.WaybillID, "rating": rating, "comment": createRequest.Comment, "created_at": createRequest.ReceivedAt, } _, err = r.collection.Create(ctx, doc)
这种方式需要手动映射字段,代码复杂度较高,适合临时场景。
验证修改
修改后重新插入文档,MongoDB会自动为每个文档生成唯一的ObjectID,不会再触发重复键错误。
内容的提问来源于stack exchange,提问作者Neighbourhood
相关产品推荐
相关产品推荐

