6

mongodb のドキュメントには次のように書かれています。

パラメーターに update 演算子式のみが含まれている場合、 および パラメーターの両方のフィールドと値。更新では、パラメーターの等価句からベース ドキュメントが作成され、パラメーターから更新式が適用されます。

そしてmgoのドキュメントには次のように書かれています:

Upsert は、指定されたセレクター ドキュメントに一致する単一のドキュメントを見つけ、更新ドキュメントに従ってそれを変更します。セレクターに一致するドキュメントが見つからない場合、更新ドキュメントがセレクター ドキュメントに適用され、結果がコレクションに挿入されます。

しかし、私がこのようなアップサートを行うと:

session.UpsertId(data.Code, data)

data.Code ではなく、mongodb によって自動的に生成された ObjectID を持つエントリになります。

これは、UpsertId がデータが更新演算子でフォーマットされることを期待しており、任意の構造体を使用できないことを意味しますか? または、ここで何が欠けていますか?

PD.Mongo 2.4.9 mgo v2 golang go バージョン 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)

}
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" }

ご覧のとおり_id、構造体のどのフィールドも にマップされていないため、アップサートで指定された は決して一致しません_id。あなたは私が持っているのと同じものが必要です:

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

これにより、フィールドが必須_idフィールドにマップされます。それ以外の場合は、自動的に作成されます。

于 2014-07-23T09:49:07.100 に答える