Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using time.Time in mongodb record

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?

like image 935
maksim Avatar asked Apr 04 '18 17:04

maksim


2 Answers

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.

like image 133
icza Avatar answered Sep 28 '22 15:09

icza


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(),
})
like image 39
Trevor V Avatar answered Sep 28 '22 15:09

Trevor V