【问题标题】:Golang mongodb mgo driver Upsert / UpsertId documentationGolang mongodb mgo 驱动程序 Upsert / UpsertId 文档
【发布时间】:2014-09-14 06:17:46
【问题描述】:

mongodb documentation 说:

如果参数仅包含更新运算符表达式,则 和 参数的字段和值。更新从参数中的等式子句创建一个基础文档,然后应用参数中的更新表达式。

mgo documentation 说:

Upsert 查找与提供的选择器文档匹配的单个文档,并根据更新文档对其进行修改。如果没有找到与选择器匹配的文档,则将更新文档应用于选择器文档并将结果插入到集合中。

但如果我做这样的更新:

session.UpsertId(data.Code, data)

我最终得到一个条目,它有一个由 mongodb 自动生成的 ObjectID,而不是 data.Code。

这意味着 UpsertId 期望数据使用更新运算符格式化,并且您不能使用任意结构?或者我在这里缺少什么?

钯。 Mongo 2.4.9 mgo v2 golang go version devel +f613443bb13a

编辑:

这是我的意思的示例,使用来自 Neil Lunn 的示例代码:

package main

import (
  "fmt"
  "gopkg.in/mgo.v2"
  // "gopkg.in/mgo.v2/bson"
)

type Person struct {
  Code string
  Name  string
}

func main() {
  session, err := mgo.Dial("admin:admin@localhost");

  if err != nil {
        fmt.Println("Error: ", err)
        return
    // panic(err)
  }

  defer session.Close()

  session.SetMode(mgo.Monotonic, true)

  c := session.DB("test").C("people")

  var p = Person{
    Code: "1234",
    Name: "Bill",
  }

  _, err = c.UpsertId( p.Code, &p )

  result := Person{}
  err = c.FindId(p.Code).One(&result)
  if err != nil {
        fmt.Println("FindId Error: ", err)
        return
    // panic(err)
  }

  fmt.Println("Person", result)

}

【问题讨论】:

    标签: mongodb go mgo


    【解决方案1】:

    您似乎在谈论在这里分配一个带有自定义 _id 字段的结构。这真的取决于你如何定义你的结构。这是一个简单的例子:

    package main
    
    import (
      "fmt"
      "gopkg.in/mgo.v2"
      "gopkg.in/mgo.v2/bson"
    )
    
    type Person struct {
      ID    string `bson:"_id"`
      Name  string
    }
    
    func main() {
      session, err := mgo.Dial("127.0.0.1");
    
      if err != nil {
        panic(err)
      }
    
      defer session.Close()
    
      session.SetMode(mgo.Monotonic, true)
    
      c := session.DB("test").C("people")
    
      var p = Person{
        ID: "1",
        Name: "Bill",
      }
    
      _, err = c.UpsertId( p.ID, &p )
    
      result := Person{}
      err = c.Find(bson.M{"_id": p.ID}).One(&result)
      if err != nil {
        panic(err)
      }
    
      fmt.Println("Person", result)
    
    }
    

    因此,在此处的自定义定义中,我将 ID 字段映射到 bson _id 并将其类型定义为字符串。如示例所示,这正是通过 UpsertId 序列化然后检索时发生的情况。


    现在您已经详细说明了,我将指出 struct 定义的不同之处。

    我已经产生了这个:

    { "_id": 1, "name": "Bill" }
    

    你所拥有的(结构上没有相同的映射)这样做:

    { "_id": ObjectId("53cfa557e248860d16e1f7e0"), "code": 1, "name": "Bill" }
    

    如您所见,在 upsert 中给出的 _id 永远不会匹配,因为您在结构中的所有字段都没有映射到 _id。你需要的和我一样:

    type Person struct {
        Code string `bson:"_id"`
        Name string
    }
    

    这会将一个字段映射到必需的 _id 字段,否则会自动为您生成一个。

    【讨论】:

    • 该结构没有 ID 字段,这就是 UpsertId 派上用场的原因。但它并没有按照 mgo 文档所说的那样做。这就是我最终出现在 mondogdb 文档中的原因。我希望 Data.Code 是 _id,但该结构没有 bson:"_id",因为它来自外部包。
    • @GabrielDíaz 否则我不确定你在问什么。看来您想提供与_id 不同的东西。这就是这段代码的作用和作用。如果你的意思不同,那么也许你可以让你的问题更清楚。 Upsert 将使用给定的 _id 值,除非有其他原因导致它不这样做。
    • 我已经用我正在做的事情编辑了你的样本。希望这有助于理解这个问题。谢谢!
    • @GabrielDíaz 如果我理解您的问题的语气,您是说 upsert 添加了它自己的 _id 值。从我的清单和你的清单之间的差异来看,原因很明显。查看结构上的映射。这就是我所说的 BSON 序列化部分。
    • 我明白你在说什么,但我的问题不同。阅读mgo驱动文档“如果没有找到与选择器匹配的文档,则将更新文档应用于选择器文档并将结果插入到集合中”,我希望Upsert将提供的Id和提供的结构合并为一个对象,然后将其插入数据库。它不起作用,那么文档中“应用”的含义是什么?
    【解决方案2】:

    我发现 MongoDB 的文档是正确的。正确的做法是将要插入的结构包装到更新运算符中。

    Neil Lunn 提供的示例代码如下所示:

    package main
    
    import (
      "fmt"
      "gopkg.in/mgo.v2"
      "gopkg.in/mgo.v2/bson"
    )
    
    type Person struct {
      Code string
      Name  string
    }
    
    func main() {
      session, err := mgo.Dial("admin:admin@localhost");
    
      if err != nil {
            fmt.Println("Error: ", err)
            return
      }
    
      defer session.Close()
    
      session.SetMode(mgo.Monotonic, true)
    
      c := session.DB("test").C("people")
    
      var p = Person{
        Code: "1234",
        Name: "Bill",
      }
        upsertdata := bson.M{ "$set": p}
    
        info , err2 := c.UpsertId( p.Code, upsertdata )
        fmt.Println("UpsertId -> ", info, err2)
      result := Person{}
      err = c.FindId(p.Code).One(&result)
      if err != nil {
            fmt.Println("FindId Error: ", err)
            return
      }
    
      fmt.Println("Person", result)
    
    }
    

    非常感谢您对尼尔的关注和帮助。

    【讨论】:

      猜你喜欢
      • 2016-01-07
      • 2018-07-28
      • 2016-01-13
      • 1970-01-01
      • 1970-01-01
      • 2019-05-27
      • 1970-01-01
      • 2015-06-15
      • 2020-02-02
      相关资源
      最近更新 更多