Go使用mongo-driver操作MongoDB如何避免存入空结构体对象
问题原因
MongoDB Go驱动的omitempty标签对值类型的结构体不生效:结构体作为值类型时,它的零值(所有字段为默认零值)不属于驱动识别的「空值」范围,因此即使赋值空结构体,也会被序列化后存入数据库。
解决方案
下面提供3种适配你需求的方案,可根据实际场景选择:
方案1:将Address字段改为指针类型(最简便)
直接修改User结构体的Address字段为AddressStruct指针类型,当字段为nil时就会触发omitempty逻辑被忽略:
type User struct { Id int `json:"id" bson:"_id,omitempty"` FirstName string `json:"first_name,omitempty" bson:"first_name,omitempty"` LastName string `json:"last_name,omitempty" bson:"last_name,omitempty"` FullName string `json:"full_name,omitempty" bson:"full_name,omitempty"` CompanyName string `json:"company_name" bson:"company_name"` // 改为指针类型 Address *AddressStruct `json:"address,omitempty" bson:"address,omitempty"` }
业务代码调整:不需要地址时不要给Address赋值,默认就是nil会自动忽略;需要存储地址时赋值结构体指针即可:
// 无地址场景,不需要赋值user.Address,直接保留默认nil即可 // 有地址场景写法 // user.Address = &AddressStruct{ // Address: "XX路XX号", // City: "北京", // // 其余字段赋值 // }
方案2:自定义AddressStruct的BSON序列化逻辑(无需修改原有字段类型)
如果不能修改Address的字段类型,你可以为AddressStruct实现MarshalBSONValue接口,判断结构体为空时直接返回空值,触发omitempty忽略逻辑,不需要给Address内部字段加omitempty标签:
首先导入依赖:
import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/bsontype" )
给AddressStruct添加序列化方法:
func (a AddressStruct) MarshalBSONValue() (bsontype.Type, []byte, error) { // 自定义空结构体判断规则,所有字段为零值则判定为空 isEmpty := a.Address == "" && a.City == "" && a.State == "" && a.Zipcode == "" && a.Apt == "" && !a.Default && a.Status == 0 && a.Country == "" && a.ShortAddress == "" if isEmpty { // 空结构体返回Undefined,触发omitempty忽略逻辑 return bsontype.Undefined, nil, nil } // 非空结构体走默认序列化逻辑,用Alias避免循环调用 type Alias AddressStruct return bson.MarshalValue(Alias(a)) }
方案3:插入前过滤空address字段
如果你不想修改结构体定义,可以在插入数据前将结构体转为BSON文档,手动删除空的address字段:
修改插入方法:
func DbInsertOne(client *mongo.Client, user User) (interface{}, error) { collection := client.Database("swatitest").Collection("users") // 先序列化为BSON再转为bson.M结构 bsonData, err := bson.Marshal(user) if err != nil { return nil, err } var doc bson.M if err = bson.Unmarshal(bsonData, &doc); err != nil { return nil, err } // 检查address是否为空对象,是的话删除该字段 if addrVal, ok := doc["address"]; ok { if addrMap, ok := addrVal.(bson.M); ok && len(addrMap) == 0 { delete(doc, "address") } } insertResult, err := collection.InsertOne(context.TODO(), doc) if err != nil { return nil, err } return insertResult.InsertedID, nil }
内容的提问来源于stack exchange,提问作者Swati
相关产品推荐
相关产品推荐

