6

I'm inserting new item in collection. Using official mongo go driver for this (https://github.com/mongodb/mongo-go-driver).

collection.InsertOne(context.Background(), map[string]interface{}{
    "string":   "test",
    "integer":  123,
    "float":    0.123,
    "array":    []string{"t", "e", "s", "t"},
    "objectid": objectid.New(),
    "time":     time.Now(),
})

But as a result I have a problem with couple of properties: time.Time and objectid.ObjectID.

  • time.Time is going as Object that is empty
  • objectid.ObjectID - as Binary

enter image description here

I understand that it's only in alpha state, but maybe someone knows. Am I just doing it wrong or it's not yet implemented in the way as it should be?

icza
  • 389,944
  • 63
  • 907
  • 827
maksim
  • 458
  • 2
  • 6
  • 16

2 Answers2

5

If you pass a map as the document to Collection.InsertOne(), the mongo package will use the mongo.TransformDocument() to convert it to a *bson.Document value, because most operations are only implemented on bson.Documents.

The current transformation implementation does not handle objectid.ObjectID nor the time.Time types. It could and probably should, and I assume it will, but currently it doesn't.

If you want these types to end up with proper types in MongoDB, you may construct and pass a *bson.Document yourself, in which you can explicitly dictate what the types of the properties should be.

This is an equivalent insert statement to yours, using bson.NewDocument() to create the document manually:

res, err := coll.InsertOne(context.Background(), bson.NewDocument(
    bson.EC.String("string", "test"),
    bson.EC.Int64("integer", 123),
    bson.EC.Double("float", 0.123),
    bson.EC.ArrayFromElements("array",
        bson.VC.String("t"), bson.VC.String("e"),
        bson.VC.String("s"), bson.VC.String("t")),
    bson.EC.ObjectID("objectid", objectid.New()),
    bson.EC.DateTime("time", time.Now().UnixNano()/1e6), // Must pass milliseconds
))

It's more verbose, but it's explicit in what we want the result document in MongoDB to be. The result document will look like this:

{
    "_id" : ObjectId("5ac5f598ca151255c6fc0ffb"),
    "string" : "test",
    "integer" : NumberLong(123),
    "float" : 0.123,
    "array" : [
        "t",
        "e",
        "s",
        "t"
    ],
    "objectid" : ObjectId("5ac5f598ca151255c6fc0ffa"),
    "time" : ISODate("2018-04-05T10:08:24.148Z")
}

Once the driver improves, I assume your original version will work as expected and produce a document identical to this in structure.

icza
  • 389,944
  • 63
  • 907
  • 827
1

You will need to convert the time to either a string or a unix timestamp. time.Now() is a type time which is a struct.

a := time.Now()
fmt.Println(a.Unix()) // Goes into mongodb as a int64
fmt.Println(a.String()) // Goes inot mongodb as a string

1522868253 // Unix

2018-04-04 13:57:33.495965 -0500 CDT m=+0.000363419 // String

So you can do this

collection.InsertOne(context.Background(), map[string]interface{}{
    "string":   "test",
    "integer":  123,
    "float":    0.123,
    "array":    []string{"t", "e", "s", "t"},
    "objectid": objectid.New(),
    "time":     time.Now().String(),
})
Trevor V
  • 1,958
  • 13
  • 33