在插入具有time.Time字段的文档时设置默认日期。

huangapple go评论68阅读模式
英文:

Set default date when inserting document with time.Time field

问题

mongoosenode.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

huangapple
  • 本文由 发表于 2017年1月28日 16:02:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/41907619.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定