mongodb - 在 Golang 的两个不同结构字段中映射 Mongo _id

标签 mongodb go struct mgo

我正在开发一个结合使用 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(类型 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 (zero value 对于 int 类型),则该字段将不会发送到 MongoDB。但是 _id属性在 MongoDB 中是强制性的,因此在这种情况下,MongoDB 服务器将生成一个 ObjectId

要克服这个问题,最简单的方法是确保 Id will 总是非零的;或者如果 0是一个有效的 ID,删除 omitempty标签中的选项。

如果您的集合必须允许混合类型的 ID(intObjectId),那么最简单的方法是定义 Id类型为 interface{} 的字段因此它可以容纳两种(实际上是所有)类型的键值:

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

是的,使用它可能有点麻烦(例如,如果您明确需要 ID 作为 int,则需要使用 type assertion),但这会解决您的问题。

如果您确实需要 2 个 ID 字段,其中一个带有 int类型和另一个 ObjectId类型,那么您唯一的选择就是实现自定义 BSON 编码(marshal)处理和解封处理。这基本上意味着实现 bson.Getter 和/或 bson.Setter 接口(interface)(每个方法一个)在你的结构类型上,你可以在其中做任何你喜欢的事情来填充你的结构或组装要实际保存/插入的数据。有关详细信息和示例,请参阅 Accessing MongoDB from Go .

这是一个使用自定义编码的示例:

省略 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 中属性(property)。

使用 GetBSON()设置方法 TempId在保存/插入结构值之前从其他 id 字段(以设置者为准),并使用 SetBSON() “复制”的方法TempId从 MongoDB 检索文档后,根据其动态类型将其值赋给其他 id 字段之一:

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
}

注意:如果您不喜欢 TempId在你的字段 Booking struct,您可以创建 Booking 的副本(例如 tempBooking ),并且只添加 TempId进去,然后使用 tempBooking用于编码/解码。您可以使用嵌入( tempBooking 可以嵌入 Booking )这样您甚至可以避免重复。

关于mongodb - 在 Golang 的两个不同结构字段中映射 Mongo _id,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51980202/

相关文章:

node.js - 仅当 mongodb 中的 operationType 为 'update' 时才过滤

go - golang 中的长查询

error-handling - 如何让 Golang 程序打印它刚刚调用的错误的行号?

Go:使用 gorilla mux 提供 CSS 文件

c++ - 我如何在单独的头文件中的结构中定义一个 char* 数组?

c - 指向结构内部结构的双指针

c - 为什么 c = 4 而不是 1 的结构中字符和 int 地址的差异

javascript - 用下划线或其他东西组合 2 个 MongoDB 集合对象?

mongodb - 在Docker容器中运行Mongo eval返回随机字符串吗?

mongodb - 如何使用 Robo 3T 从 MongoDB 导出 JSON