使用Go访问MongoDB

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

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中的EndDatestring形式存储,所以我将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.Getterbson.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.Getterbson.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

huangapple
  • 本文由 发表于 2017年2月20日 19:08:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/42342943.html
匿名

发表评论

匿名网友

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

确定