jjzjj

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

coder 2023-06-28 原文

我正在开发一个结合使用 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/

有关mongodb - 在 Golang 的两个不同结构字段中映射 Mongo _id的更多相关文章

  1. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  2. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  3. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  4. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  5. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

  6. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  7. ruby - 具有两个参数的 block - 2

    我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

  8. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  9. ruby-on-rails - Sphinx - 何时对字段使用 'has' 和 'indexes' - 2

    我几天前在我的ruby​​onrails2.3.2上安装了Sphinx和Thinking-Sphinx,基本搜索效果很好。这意味着,没有任何条件。现在,我想用一些条件过滤搜索。我有公告模型,索引如下所示:define_indexdoindexestitle,:as=>:title,:sortable=>trueindexesdescription,:as=>:description,:sortable=>trueend也许我错了,但我注意到只有当我将:sortable=>true语法添加到这些属性时,我才能将它们用作搜索条件。否则它找不到任何东西。现在,我还在使用acts_as_tag

  10. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

    假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

随机推荐