dougang6821 2018-08-23 07:12
浏览 330

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

I am working on a project that uses combination of Go and MongoDB. I am stuck at a place where I have a struct like:

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"`
    }

In this struct, the field Id is of int type. But as we know MongoDB's default id is of bsonObject type. Some times, the system generates the default MongoDB id in Id field.

To overcome this I have modified the struct like this:

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"`
        }

In above struct, I have mapped the same _id field in two different struct fields Id (type int) and BsonId (type bson.ObjectId). I want if id of integer type comes, it maps under Id otherwise under BsonId.

But this thing is giving following error:

Duplicated key '_id' in struct models.Booking

How can I implement this type of thing with Go Structs ??

Update:

Here is the code I have written for custom marshaling/unmarshaling:

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
}

But this is giving type mismatch error of Id and BsonId fields. What should I do now ?

  • 写回答

1条回答 默认 最新

  • dongshan1036 2018-08-23 07:24
    关注

    In your original struct you used this tag for the Id field:

    bson:"_id,omitempty"
    

    This means if the value of the Id field is 0 (zero value for the int type), then that field will not be sent to MongoDB. But the _id property is mandatory in MongoDB, so in this case the MongoDB server will generate an ObjectId for it.

    To overcome this, the easiest is to ensure the Id will is always non-zero; or if the 0 is a valid id, remove the omitempty option from the tag.

    If your collection must allow ids of mixed type (int and ObjectId), then the easiest would be to define the Id field with type of interface{} so it can accomodate both (actually all) types of key values:

    Id interface{} `json:"_id,omitempty" bson:"_id,omitempty"`
    

    Yes, working with this may be a little more cumbersome (e.g. if you explicitly need the id as int, you need to use type assertion), but this will solve your issue.

    If you do need 2 id fields, one with int type and another with ObjectId type, then your only option will be to implement custom BSON marshaling and unmarshaling. This basically means to implement the bson.Getter and / or bson.Setter interfaces (one method for each) on your struct type, in which you may do anything you like to populate your struct or assemble the data to be actually saved / inserted. For details and example, see Accessing MongoDB from Go.

    Here's an example how using custom marshaling it may look like:

    Leave out the Id and BsonId fields from marshaling (using the bson:"-" tag), and add a 3rd, "temporary" id field:

    type Booking struct {
            Id     int           `bson:"-"`
            BsonId bson.ObjectId `bson:"-"`
            TempId interface{}   `bson:"_id"`
            // rest of your fields...
    }
    

    So whatever id you have in your MongoDB, it will end up in TempId, and only this id field will be sent and saved in MongoDB's _id property.

    Use the GetBSON() method to set TempId from the other id fields (whichever is set) before your struct value gets saved / inserted, and use SetBSON() method to "copy" TempId's value to one of the other id fields based on its dynamic type after the document is retrieved from 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
    }
    

    Note: if you dislike the TempId field in your Booking struct, you may create a copy of Booking (e.g. tempBooking), and only add TempId into that, and use tempBooking for marshaling / unmarshaling. You may use embedding (tempBooking may embed Booking) so you can even avoid repetition.

    评论

报告相同问题?

悬赏问题

  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)
  • ¥20 matlab yalmip kkt 双层优化问题