英文:
Accessing MongoDB from Go
问题
我正在使用Go访问MongoDB,代码如下:
var configRes *clientConfigData
err := clientDB.
C(clientConfigCollection).
Find(bson.M{}).
One(&configRes)
if err != nil {
return nil, errors.Wrap(err, "finding config collection")
}
其中,
type clientConfigData struct {
SMTPAssoc int `bson:"smtp_assoc"`
PlanType string `bson:"plan_type"`
EndDate string `bson:"end_date"`
}
由于MongoDB中的EndDate
以string
形式存储,所以我将EndDate
声明为string
。但是我需要将这个日期作为Go中的Time
类型访问clientConfigData
。
英文:
I am accessing MongoDB using Go as follows:
var configRes *clientConfigData
err := clientDB.
C(clientConfigCollection).
Find(bson.M{}).
One(&configRes)
if err != nil {
return nil, errors.Wrap(err, "finding config collection")
}
Where
type clientConfigData struct {
SMTPAssoc int `bson:"smtp_assoc"`
PlanType string `bson:"plan_type"`
EndDate string `bson:"end_date"`
}
Now since EndDate
in MongoDB is stored as string
so I declared EndDate
as string
. But I need to access this date as Go Time
in clientConfigData
.
答案1
得分: 2
如果您想在将值从MongoDB进行编组/解组时更改值或进行类型转换,可以通过实现自定义的编组/解组逻辑来实现。
您可以通过实现bson.Getter
和bson.Setter
接口来实现这一点。在这些方法内部,您可以对进行编组/解组的值进行任何操作。
最简单的方法是通过为您的clientConfigData
类型扩展一个额外的字段,该字段将是time.Time
类型,即您所需的值:
type clientConfigData struct {
SMTPAssoc int `bson:"smtp_assoc"`
PlanType string `bson:"plan_type"`
EndDateStr string `bson:"end_date"`
EndDate time.Time `bson:"-"`
}
它的标签值为bson:"-"
,因为我们不希望它出现在MongoDB中。
现在是自定义的编组/解组逻辑:
const endDateLayout = "2006-01-02 15:04:05" // 在这里使用您的布局
func (c *clientConfigData) SetBSON(raw bson.Raw) (err error) {
type my clientConfigData
if err = raw.Unmarshal((*my)(c)); err != nil {
return
}
c.EndDate, err = time.Parse(endDateLayout, c.EndDateStr)
return
}
func (c *clientConfigData) GetBSON() (interface{}, error) {
c.EndDateStr = c.EndDate.Format(endDateLayout)
type my *clientConfigData
return my(c), nil
}
这里发生的情况是,SetBSON()
负责使用来自MongoDB的原始值“填充”您的结构值,而GetBSON()
负责提供您希望保存(编组)的值。
加载时:SetBSON()
首先将值按原样解组,然后从来自数据库的string
日期值(EndDateStr
)正确设置EndDate
字段(其类型为time.Time
)。
保存时:GetBSON()
首先从EndDate
字段填充EndDateStr
字段(保存的字段),然后简单地返回,表示可以保存。
需要注意的一点是,SetBSON()
和GetBSON()
都在其中创建了一个新的my
类型。这样做的原因是为了避免堆栈溢出。简单地返回clientConfigData
类型的值是不好的,因为我们实现了bson.Getter
和bson.Setter
,所以SetBSON()
和GetBSON()
会被无限调用。新的my
类型没有这些方法,因此不会发生无限的“递归”(type
关键字创建了一个新类型,并且它不会“继承”基础类型的方法)。
还请参阅相关/类似的问题:https://stackoverflow.com/questions/41907619/set-default-date-when-inserting-document-with-time-time-field/42344267#42344267
英文:
If you want to change a value or do a type conversion when marshaling / unmarshaling your values from / to MongoDB, you may do it by implementing a custom marshaling / unmarshaling logic.
You can do this by implementing the bson.Getter
and bson.Setter
interfaces. Inside these methods, you may do whatever you want to with the values being marshaled / unmarshaled.
Easiest is to extend your clientConfigData
type with an additional field, one that will be of type time.Time
, the value you need:
type clientConfigData struct {
SMTPAssoc int `bson:"smtp_assoc"`
PlanType string `bson:"plan_type"`
EndDateStr string `bson:"end_date"`
EndDate time.Time `bson:"-"`
}
It has tag value bson:"-"
, because we don't want this to appear in MongoDB.
And now the custom marshaling / unmarhsaling logic:
const endDateLayout = "2006-01-02 15:04:05" // Use your layout here
func (c *clientConfigData) SetBSON(raw bson.Raw) (err error) {
type my clientConfigData
if err = raw.Unmarshal((*my)(c)); err != nil {
return
}
c.EndDate, err = time.Parse(endDateLayout, c.EndDateStr)
return
}
func (c *clientConfigData) GetBSON() (interface{}, error) {
c.EndDateStr = c.EndDate.Format(endDateLayout)
type my *clientConfigData
return my(c), nil
}
What happens here is that SetBSON()
is responsible to "populate" your struct value with the raw value coming from MongoDB, and GetBSON()
is responsible to provide a value you want to be saved (marshaled).
When loading: SetBSON()
first unmarshals the value as-is, then properly sets the EndDate
field (which is of type time.Time
) from the string
date value that came from the DB (EndDateStr
).
When saving: GetBSON()
first fills the EndDateStr
field (the one that is saved) from the EndDate
field, and then simply returns, signaling that it is ok to save.
One thing to note: both SetBSON()
and GetBSON()
create a new my
type inside them. The reason for this is to avoid stack overflow. Simply returning a value of type clientConfigData
is bad, because we implemented bson.Getter
and bson.Setter
, so SetBSON()
and GetBSON()
would get called endlessly. The new my
type does not have these methods, so endless "recursion" does not happen (the type
keyword creates a new type, and it does not "inherit" methods of the underlying type).
Also see related / similar question: https://stackoverflow.com/questions/41907619/set-default-date-when-inserting-document-with-time-time-field/42344267#42344267
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论