Golang mongodb mgo драйвер Документация Upsert / UpsertId

Документация mongodb гласит:

Поля и значения обоих параметров и, если параметр содержит только выражения оператора обновления. Обновление создает базовый документ из предложений равенства в параметре, а затем применяет выражения обновления из параметра.

И документация MGO гласит:

Upsert находит один документ, соответствующий предоставленному документу селектора, и модифицирует его в соответствии с документом обновления. Если документ, соответствующий селектору, не найден, документ обновления применяется к документу селектора, и результат вставляется в коллекцию.

Но если я сделаю упадок, как это:

session.UpsertId(data.Code, data)

В итоге я получаю запись, в которой ObjectID автоматически сгенерирован с помощью mongodb, а не data.Code.

это означает, что UpsertId ожидает, что данные будут отформатированы с помощью операторов обновления, и вы не можете использовать произвольную структуру? Или чего мне здесь не хватает?

Оплаченный Mongo 2.4.9 mgo v2 golang go версия devel +f613443bb13a

РЕДАКТИРОВАТЬ:

Это пример того, что я имею в виду, используя пример кода от Нила Ланна:

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)

}

2 ответа

Я обнаружил, что документация MongoDB была правильной. Правильный способ сделать это - обернуть структуру для вставки в оператор обновления.

Пример кода, предоставленный Нилом Ланном, будет выглядеть так:

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)

}

Большое спасибо за ваш интерес и помощь, Нил.

Вы, кажется, говорите о назначении структуры с пользовательским _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)

}

Так что в пользовательском определении здесь я отображаю поле идентификатора в BSON _id и определение его типа в виде строки. Как показано в примере, это именно то, что происходит, когда сериализуется через UpsertId, а затем извлекается.


Теперь вы уточнили, я укажу на разницу на struct определение.

Что у меня получается так:

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

То, что у вас есть (без того же отображения в структуре), делает это:

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

Как видите, _id данные в upsert никогда не будут совпадать, потому что ни одно из ваших полей в структуре не сопоставлено с _id, Тебе нужно так же, как и мне:

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

Это сопоставляет поле с обязательным _id поле, иначе один автоматически создается для вас.

Другие вопросы по тегам