time.Time being stored as string instead of date (via interface{})

33 views
Skip to first unread message

Kris Runzer

unread,
Mar 14, 2016, 6:23:10 PM3/14/16
to mgo-users
Hello,

I have the following structs:

type Record struct {
RecordID      string     `json:"recordID" bson:"_id"`
CreatedOn     time.Time  `json:"createdOn" bson:"created_on"`
LastUpdatedOn time.Time  `json:"lastUpdatedOn" bson:"last_updated_on"`
Kind          Kind       `json:"kind" bson:"kind"`
Data          RecordData `json:"data" bson:"data"`
}

// RecordData is a map of typed-backed key-values for a Record
type RecordData map[string]TypedValue

// SetString adds a new key with a string value
func (d RecordData) SetString(name, value string) {
d[name] = TypedValue{Type: ValueTypeString, Value: value}
}

// SetNumber adds a new key with a float64 value
func (d RecordData) SetNumber(name string, value float64) {
d[name] = TypedValue{Type: ValueTypeNumber, Value: value}
}

// SetDate adds a new key with a time.Time value
func (d RecordData) SetDate(name string, value time.Time) {
d[name] = TypedValue{Type: ValueTypeDate, Value: value}
}

// TypedValue bundles a interface{} with a ValueType
type TypedValue struct {
Type  ValueType   `json:"type" bson:"type"`
Value interface{} `json:"value" bson:"value"`
}

// ValueType specifies the type of a TypedValue
type ValueType string

const (
// ValueTypeString specifies the Value is of type String
ValueTypeString ValueType = "string"
// ValueTypeNumber specifies the Value is of type float64
ValueTypeNumber ValueType = "number"
// ValueTypeDate specifies the Value is of type time.Time
ValueTypeDate ValueType = "date"
)

If I store the following struct: 

rd := ps.RecordData{}
rd
.SetDate("status_date", time.Now())
rd
.SetString("status_severity", "asdf")
rd
.SetNumber("status_codes", 1123.0)

I get the following in mongo:

"status_date" : {
    "type" : "date",
   
"value" : "2016-03-14T15:13:55.5802835-07:00"  // I would expect this to be an ISODate()
},
"status_severity" : {
   
"type" : "string",
   
"value" : "asdf"
},
"status_codes" : {
    "type" : "number",
   
"value" : 1123.0
}

Here is the mgo operation doing the upsert:

func (s *store) Upsert(id string, kind spec.Kind, data spec.RecordData) (response spec.Record, err error) {
s.mgoSearchHandler(func(db *mgo.Database) {
now := time.Now()

set := bson.M{
"last_updated_on": now,
}

for key, val := range data {
set["data."+key] = val
}

change := mgo.Change{
ReturnNew: true,
Upsert:    true,
Update: bson.M{
"$set": set,
"$setOnInsert": bson.M{
"_id":        id,
"created_on": now,
"kind":       kind,
},
},
}

_, err = db.C(cSearchRecords).FindId(id).Apply(change, &response)
})

return response, err
}

Is there something I am missing when working with interface{} that is causing this date to be a string instead of a ISODate()?  Is my storing method the culprit (type information is being lost somewhere)?
)

Thank you,
Kris

David Marchbanks

unread,
Mar 15, 2016, 7:40:13 AM3/15/16
to mgo-users
The same happens if you Marshall it into JSON. If you wanted it to come out differently, I believe you would need to write your own type with a Marshall.

Gustavo Niemeyer

unread,
Mar 15, 2016, 9:12:19 AM3/15/16
to mgo-...@googlegroups.com
Hi Kris,

Your expectation is correct.. it should indeed be written into the database as a date/time value, and in my local tests it actually does that fine.

I suggest trying to reduce your code to a simpler self-contained example. You'll probably find the problem on the way.

To ensure there are no obvious bugs, I did the same here:


Here is what gets written into the database:

> db.somevalues.find()
{ "_id" : ObjectId("56e8071ceb98a01a0f8db3a8"), "value" : ISODate("2016-03-15T12:59:08.295Z") }
> db.morevalues.find()
{ "_id" : 42, "field" : { "value" : ISODate("2016-03-15T12:59:08.296Z") } }


 

--
You received this message because you are subscribed to the Google Groups "mgo-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mgo-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Gustavo Niemeyer

unread,
Mar 15, 2016, 9:19:12 AM3/15/16
to mgo-...@googlegroups.com
It happens in json because there's no native way to represent times and dates there.

BSON has a native type for those, though, and mgo's bson package supports it well. It should be stored exactly as expected in that case. 

--
You received this message because you are subscribed to the Google Groups "mgo-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mgo-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages