英文:
Set default date when inserting document with time.Time field
问题
在mongoose
(node.js
)中,我可以像这样使用默认的Date.now
定义模型架构:
...
type: Date,
default: Date.now
...
在使用mgo
创建文档时,如何实现不必每次都插入time.Time
的相同效果?
type User struct {
CreatedAt time.Time `json:"created_at" bson:"created_at"` // 每次插入此`struct`的文档时,使此字段自动填充为time.Now()
}
英文:
In mongoose
(node.js
) I can define a model schema with a default Date.now
like so:
...
type: Date,
default: Date.now
...
How do I achieve the same without having to insert the time.Time
every time I create a document with mgo
?
type User struct {
CreatedAt time.Time `json:"created_at" bson:"created_at"` // Make this field filled automatically with time.Now() every time a document of this `struct` is inserted
}
答案1
得分: 8
在Go语言中,无法为字段定义默认值,当创建一个新的结构体值时,它们将始终是其类型的零值(除非使用复合字面量,在其中可以显式地给出不同的值)。
因此,一种选择是创建一个类似构造函数的函数NewUser()
,该函数将设置该字段,并始终使用此函数来创建新的用户:
func NewUser() *User {
return &User{
CreatedAt: time.Now(),
}
}
当然,这不能强制执行,并且这将保存User
结构值创建的时间戳,而不是保存时的时间。
另一种更好的方法是使用自定义的编组逻辑。
您可以通过实现bson.Getter
来编写自定义的编组逻辑。GetBSON()
负责提供实际保存的值。我们希望保存相同的User
实例,只是在之前设置其CreatedAt
字段:
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
}
请注意,创建并返回了一个新的my
类型。这样做的原因是为了避免堆栈溢出。简单地返回*User
类型的值是不好的,因为它实现了bson.Getter
,所以GetBSON()
会无限调用。新的my
类型没有这个方法,因此不会发生无限的“递归”(type
关键字创建了一个新类型,并且它不会“继承”基础类型的方法)。
请注意,即使您只想重新保存User
,此解决方案也会覆盖(重新设置)CreatedAt
字段。因此,我们应该添加一个检查,检查CreatedAt
字段是否已填充,并且只有在其为零值时才设置它:
func (u *User) GetBSON() (interface{}, error) {
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now()
}
type my *User
return my(u), nil
}
还请参阅相关/类似的问题:https://stackoverflow.com/questions/42342943/accesing-mongodb-from-go/42343810#42343810
英文:
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: https://stackoverflow.com/questions/42342943/accesing-mongodb-from-go/42343810#42343810
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论