6

mongodb 文档说:

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

mgo文档说:

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

但如果我做这样的更新:

session.UpsertId(data.Code, data)

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

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

钯。Mongo 2.4.9 mgo v2 golang go版本开发+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)

}
4

2 回答 2

4

我发现 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)

}

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

于 2014-07-23T14:31:07.700 回答
2

您似乎在谈论在_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" }

您所拥有的(在 struct 上没有相同的映射)执行以下操作:

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

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

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

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

于 2014-07-23T09:49:07.100 回答