繁体   English   中英

在Golang中的两个不同struct字段中映射Mongo _id

[英]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"`
    }

在此结构中,字段Idint类型。 但是我们知道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字段的值为0int类型的值为零 ),则该字段不会发送到MongoDB。 但是_id属性在MongoDB中是必需的,因此在这种情况下,MongoDB服务器将为其生成ObjectId

为了克服这个问题,最简单的方法是确保Id始终为非零; 或者,如果0是有效的ID,则从标记中删除omitempty选项。

如果您的集合必须允许使用混合类型的ID( intObjectId ),那么最简单的方法是使用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

这是一个使用自定义封送处理的样子的示例:

从封送处理中排除IdBsonId字段(使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM