Go后端MongoDB用户注册出现重复id字段问题求助
我用Go后端搭配MongoDB实现用户注册逻辑,需要通过JSON和前端传输数据,同时用BSON和MongoDB交互,定义的User模型和注册函数如下:
User模型代码
package database type User struct { ID primitive.ObjectID `json:"_id,omitempty", bson:"_id,omitempty"` Role string `json:"role,omitempty, "bson:"role,omitempty"` Name string `json:"name,omitempty", bson:"name,omitempty"` Email string `json:"email,omitempty", bson:"email,omitempty"` Favorites []primitive.ObjectID `json:"favorites,omitempty", bson:"favorites,omitempty"` Password []byte `json:"-", bson:"password,omitempty"` }
注册函数代码
func Register(c *fiber.Ctx) error { fmt.Println("Registering user.") var data map[string]string if err := c.BodyParser(&data); err != nil { return err } // check if email already used var user database.User if err := database.Users.FindOne(c.Context(), bson.M{"email": data["email"]}).Decode(&user); err == nil { c.Status(fiber.StatusBadRequest) return c.JSON(fiber.Map{ "message": "Email already in use", }) } password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14) user = database.User{ Role: "viewer", Name: data["name"], Email: data["email"], Password: password, } result, err := database.Users.InsertOne(c.Context(), user) fmt.Println("Inserted user to database") if err != nil { return err } return c.JSON(result) }
目前逻辑能正常运行,但数据库里总会多出一个值全为0的无下划线id字段。删掉ID字段的JSON标签只留BSON标签能解决问题,但我需要保留JSON配置,也不想为数据库和客户端分别定义模型增加复杂度,因此有两个问题:
- 为什么会出现这种情况?
- 有没有无需增加复杂度的解决办法?
1. 冗余id字段出现的原因
你在结构体标签里犯了语法错误:JSON和BSON标签之间用了逗号加空格的分隔方式,这会让Go的结构体标签解析器把逗号当作标签的一部分,导致BSON标签解析异常。
以ID字段为例,你写的json:"_id,omitempty", bson:"_id,omitempty"会被解析器误判:", bson:"_id,omitempty"成了JSON标签的一部分,而BSON标签实际被解析为空。这时MongoDB驱动会默认把结构体字段名ID转成小写的id存入数据库,同时因为没有正确设置BSON的_id标签,驱动又会自动生成一个_id字段,最终就出现了两个ID相关字段:一个是意外生成的全0值id,另一个是MongoDB自动创建的_id。
其他字段的标签也存在同样问题,比如Role字段的json:"role,omitempty, "bson:"role,omitempty",JSON标签里多了逗号和空格,同样会导致解析异常。
2. 无需增加复杂度的解决办法
直接修正结构体标签的语法:JSON和BSON标签之间只用空格分隔,不要加逗号。正确的User模型定义如下:
package database type User struct { ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` Role string `json:"role,omitempty" bson:"role,omitempty"` Name string `json:"name,omitempty" bson:"name,omitempty"` Email string `json:"email,omitempty" bson:"email,omitempty"` Favorites []primitive.ObjectID `json:"favorites,omitempty" bson:"favorites,omitempty"` Password []byte `json:"-" bson:"password,omitempty"` }
修正后,Go的标签解析器能正确识别JSON和BSON各自的标签,MongoDB驱动会按照bson:"_id,omitempty"的设置处理ID字段,不会再生成冗余的id字段,同时JSON标签也能正常生效,满足和前端交互的需求。
另外提个小建议:注册函数里忽略了bcrypt.GenerateFromPassword的错误,建议加上错误处理,避免密码加密失败的情况。
内容的提问来源于stack exchange,提问作者Andy Frey

