简体   繁体   English

Golang mongodb mgo driver Upsert / UpsertId文档

[英]Golang mongodb mgo driver Upsert / UpsertId documentation

The mongodb documentation says: mongodb文档说:

The fields and values of both the and parameters if the parameter contains only update operator expressions. 如果参数仅包含更新运算符表达式,则为和参数的字段和值。 The update creates a base document from the equality clauses in the parameter, and then applies the update expressions from the parameter. 此更新根据参数中的等于子句创建基本文档,然后应用参数中的更新表达式。

And the mgo documentation says: 并且mgo文档说:

Upsert finds a single document matching the provided selector document and modifies it according to the update document. Upsert查找与提供的选择器文档匹配的单个文档,并根据更新文档对其进行修改。 If no document matching the selector is found, the update document is applied to the selector document and the result is inserted in the collection. 如果找不到与选择器匹配的文档,则将更新文档应用于选择器文档,并将结果插入到集合中。

But if i do an upsert like this: 但如果我像这样做一个upsert:

session.UpsertId(data.Code, data)

I end up with an entry which have an ObjectID generated automatically by mongodb, instead of data.Code. 我最终得到一个条目,它具有由mongodb自动生成的ObjectID,而不是data.Code。

this means that UpsertId expect data to be formated with update operators and you can't use a an arbitrary struct? 这意味着UpsertId期望使用更新运算符格式化数据,并且您不能使用任意结构? Or what i'm missing here? 或者我在这里失踪了什么?

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

EDIT: 编辑:

This is a sample of what i mean, using the sample code from Neil Lunn: 这是我的意思的样本,使用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)

}

I found the documentation of the MongoDB was right. 我发现MongoDB的文档是对的。 The correct way to do this is to wrap the struct to insert into an update operator. 执行此操作的正确方法是将结构包装到插入更新运算符中。

The sample code provided by Neil Lunn, would look like: 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)

}

Thank you very much for your interest and help Neil. 非常感谢您的关注和帮助Neil。

You seem to be talking about assigning a struct with a custom _id field here. 您似乎在谈论在此处为自定义_id字段分配结构。 This really comes down to how you define your struct. 这实际上取决于您如何定义结构。 Here is a quick example: 这是一个简单的例子:

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)

}

So in the custom definition here I am mapping the ID field to bson _id and defining it's type as string. 所以在这里的自定义定义中,我将ID字段映射到bson _id并将其类型定义为字符串。 As shown in the example this is exactly what happens when serialized via UpsertId and then retrieved. 如示例所示,这正是通过UpsertId序列化然后检索时发生的情况。


Now you have elaborated I'll point to the difference on the struct definition. 现在你已经详细说明了我将指出struct定义的不同之处。

What I have produces this: 我得到的是:

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

What you have ( without the same mapping on the struct ) does this: 你有什么(在结构上没有相同的映射)这样做:

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

As you see, the _id given in the upsert will never match because none of your fields in the struct are mapped to _id . 如您所见,upsert中给出的_id将永远不会匹配,因为结构中的所有字段都不会映射到_id You need the same as I have: 你需要和我一样:

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

That maps a field to the mandatory _id field, otherwise one is automatically produced for you. 将字段映射到强制_id字段,否则会自动为您生成一个字段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM