[英]Map Mongo _id in two different struct fields in Golang
我正在开发一个使用Go和MongoDB组合的项目。 我被卡在一个结构类似的地方:
type Booking struct {
// booking fields
Id int `json:"_id,omitempty" bson:"_id,omitempty"`
Uid int `json:"uid,omitempty" bson:"uid,omitempty"`
IndustryId int `json:"industry_id,omitempty" bson:"industry_id,omitempty"`
LocationId int `json:"location_id,omitempty" bson:"location_id,omitempty"`
BaseLocationId int `json:"base_location_id,omitempty" bson:"base_location_id,omitempty"`
}
在此结构中,字段Id
为int
类型。 但是我们知道MongoDB的默认ID是bsonObject
类型。 有时,系统会在Id
字段中生成默认的MongoDB ID。
为了克服这个问题,我修改了这样的结构:
type Booking struct {
// booking fields
Id int `json:"_id,omitempty" bson:"_id,omitempty"`
BsonId bson.ObjectId `json:"bson_id" bson:"_id,omitempty"`
Uid int `json:"uid,omitempty" bson:"uid,omitempty"`
IndustryId int `json:"industry_id,omitempty" bson:"industry_id,omitempty"`
LocationId int `json:"location_id,omitempty" bson:"location_id,omitempty"`
BaseLocationId int `json:"base_location_id,omitempty" bson:"base_location_id,omitempty"`
}
在上面的结构中,我已将相同的_id
字段映射到两个不同的结构字段Id(类型为int)和BsonId
(类型为bson.ObjectId
)中。 我想要如果整数类型的id出现,则它在Id
下映射,否则在BsonId
下。
但是,这件事给下面的错误:
Duplicated key '_id' in struct models.Booking
如何使用Go Structs实现这种类型的东西?
更新:
这是我为自定义封送/拆组编写的代码:
func (booking *Booking) SetBSON(raw bson.Raw) (err error) {
type bsonBooking Booking
if err = raw.Unmarshal((*bsonBooking)(booking)); err != nil {
return
}
booking.BsonId, err = booking.Id
return
}
func (booking *Booking) GetBSON() (interface{}, error) {
booking.Id = Booking.BsonId
type bsonBooking *Booking
return bsonBooking(booking), nil
}
但这给出了Id和BsonId字段的类型不匹配错误。 我现在应该怎么办 ?
在您的原始结构中,您将此标签用于Id
字段:
bson:"_id,omitempty"
这意味着,如果Id
字段的值为0
( int
类型的值为零 ),则该字段不会发送到MongoDB。 但是_id
属性在MongoDB中是必需的,因此在这种情况下,MongoDB服务器将为其生成ObjectId
。
为了克服这个问题,最简单的方法是确保Id
始终为非零; 或者,如果0
是有效的ID,则从标记中删除omitempty
选项。
如果您的集合必须允许使用混合类型的ID( int
和ObjectId
),那么最简单的方法是使用interface{}
类型定义Id
字段,以便它可以容纳(实际上是所有)两种类型的键值:
Id interface{} `json:"_id,omitempty" bson:"_id,omitempty"`
是的,使用它可能会比较麻烦(例如,如果您明确地将id用作int
,则需要使用type assertion ),但这将解决您的问题。
如果您确实需要2个id字段,一个具有int
类型,另一个具有ObjectId
类型,那么您唯一的选择将是实现自定义BSON封送处理和取消封送处理。 这基本上意味着在您的结构类型上实现bson.Getter
和/或bson.Setter
接口(每个接口一个方法),您可以在其中进行任何您想填充其结构或组装要实际保存/插入的数据的操作。 有关详细信息和示例,请参阅从Go访问MongoDB 。
这是一个使用自定义封送处理的样子的示例:
从封送处理中排除Id
和BsonId
字段(使用bson:"-"
标签),然后添加第三个“临时” id字段:
type Booking struct {
Id int `bson:"-"`
BsonId bson.ObjectId `bson:"-"`
TempId interface{} `bson:"_id"`
// rest of your fields...
}
因此,无论您在MongoDB中拥有什么id,它都将以TempId
,并且仅此id字段将被发送并保存在MongoDB的_id
属性中。
使用GetBSON()
方法来设置TempId
从其它ID字段(取其设置),你的结构值获取保存/插入之前,用SetBSON()
方法来“复制” TempId
基础的价值的其它ID领域之一从MongoDB中检索文档后,将其动态类型更改为:
func (b *Booking) GetBSON() (interface{}, error) {
if b.Id != 0 {
b.TempId = b.Id
} else {
b.TempId = b.BsonId
}
return b, nil
}
func (b *Booking) SetBSON(raw bson.Raw) (err error) {
if err = raw.Unmarshal(b); err != nil {
return
}
if intId, ok := b.TempId.(int); ok {
b.Id = intId
} else bsonId, ok := b.TempId.(bson.ObjectId); ok {
b.BsonId = bsonId
} else {
err = errors.New("invalid or missing id")
}
return
}
注意:如果您不喜欢Booking
结构中的TempId
字段,则可以创建Booking
的副本(例如tempBooking
),并仅将TempId
添加到其中,然后使用tempBooking
进行编组/ tempBooking
。 您可以使用嵌入( tempBooking
可以嵌入Booking
),因此甚至可以避免重复。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.