In mongoose
(node.js
) I can define a model schema with a default Date.now
like so:
...
type: Date,
default: Date.now
..
In Go you can't define default values for fields, they will always be the zero-value of their type when a new struct value is created (unless you use a composite literal where you can give a different value explicitly).
So one option would be to create a constructor-like function NewUser()
which would set this field, and use always this function to create new users:
func NewUser() *User {
return &User{
CreatedAt: time.Now(),
}
}
Of course this can't be forced, and also this will hold the timestamp of the User
struct value creation and not when it is saved.
Another, better approach is to use a custom marshaling logic.
You can write custom marshaling logic by implementing bson.Getter. GetBSON()
is responsible to provide a value that will actually be saved. We want the same User
instance to be saved, just its CreatedAt
field set prior:
type User struct {
CreatedAt time.Time `json:"created_at" bson:"created_at"`
}
func (u *User) GetBSON() (interface{}, error) {
u.CreatedAt = time.Now()
type my *User
return my(u), nil
}
Note that a new my
type is created and returned. The reason for this is to avoid stack overflow. Simply returning a value of type *User
is bad, because it implements bson.Getter
, so GetBSON()
would get called endlessly. The new my
type does not have this method, so endless "recursion" does not happen (the type
keyword creates a new type, and it does not "inherit" methods of the underlying type).
Note that this solution will also overwrite (re-set) the CreatedAt
field) even if you just want to re-save a User
. So we should add a check whether the CreatedAt
field is filled, and only set it if it's the zero value:
func (u *User) GetBSON() (interface{}, error) {
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now()
}
type my *User
return my(u), nil
}
Also see related / similar question: Accesing MongoDB from Go