Golang mongodb mgo driver Upsert / UpsertId documentation

Gabriel Díaz picture Gabriel Díaz · Jul 23, 2014 · Viewed 15.8k times · Source

The mongodb documentation says:

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:

Upsert finds a single document matching the provided selector document and modifies it according to the update document. 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:

session.UpsertId(data.Code, data)

I end up with an entry which have an ObjectID generated automatically by mongodb, instead of data.Code.

this means that UpsertId expect data to be formated with update operators and you can't use a an arbitrary struct? Or what i'm missing here?

Pd. 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:

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)

}

Answer

Gabriel Díaz picture Gabriel Díaz · Jul 23, 2014

I found the documentation of the MongoDB was right. 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:

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.