mongo对于时间戳序列化MarshalBSON和UnmarshalBSON的操作
问题原因
使用官方mongo驱动go.mongodb.org/mongo-driver, 或七牛云github.com/qiniu/qmgo ,查询出来的json时间字段很不友好.
{
"createTime": "2023-09-08T06:36:55.234Z",
"description": "时间格式不友好"
}
我们想要的时间格式 :
{
"createTime": "2023-10-08 15:53:19",
"description": "时间格式友好"
}
解决办法
自定义一个时间类型, 使用 MarshalBSONValue 和 UnmarshalBSONValue 将时间格式化为 yyyy-MM-dd HH:mm:ss这种格式.
import (
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"time"
)
// Time is alias type for time.Time
// mysql 时间格式化 和 gorm的Scan/Value的实现类
type Time time.Time
// UnmarshalJSON implements json unmarshal interface.
func (t *Time) UnmarshalJSON(data []byte) (err error) {
now, err := time.ParseInLocation(`"`+time.DateTime+`"`, string(data), time.Local)
*t = Time(now)
return
}
// MarshalJSON implements json marshal interface.
func (t Time) MarshalJSON() ([]byte, error) {
b := make([]byte, 0, len(time.DateTime)+2)
b = append(b, '"')
b = time.Time(t).AppendFormat(b, time.DateTime)
b = append(b, '"')
return b, nil
}
// MarshalBSONValue mongodb是存储bson格式,因此需要实现序列化bsonvalue(这里不能实现MarshalBSON,MarshalBSON是处理Document的),将时间转换成mongodb能识别的primitive.DateTime
func (t *Time) MarshalBSONValue() (bsontype.Type, []byte, error) {
targetTime := primitive.NewDateTimeFromTime(time.Time(*t))
return bson.MarshalValue(targetTime)
}
// UnmarshalBSONValue 实现bson反序列化,从mongodb中读取数据转换成time.Time格式,这里用到了bsoncore中的方法读取数据转换成datetime然后再转换成time.Time
func (t *Time) UnmarshalBSONValue(t2 bsontype.Type, data []byte) error {
v, _, valid := bsoncore.ReadValue(data, t2)
if valid == false {
return errors.New(fmt.Sprintf("%s, %s, %s", "读取数据失败:", t2, data))
}
if v.Type == bsontype.DateTime {
*t = Time(v.Time())
}
return nil
}
使用举例
定义一个结构体, 使用上面的自定义类型作为字段类型.
type ProducerMessage struct {
Id string `bson:"_id" json:"id"`
//消息id
MessagesId string `bson:"messagesId" json:"messagesId"`
//消息
Message string `bson:"message" json:"message"`
//创建时间
CreateTime *Time `bson:"createTime" json:"createTime"`
//更新时间
UpdateTime *Time `bson:"updateTime" json:"updateTime"`
}
构造对象.
// 获取当前时间
func GetNowTimestamp() *Time {
// 强制类型转换
uTime := Time(time.Now())
return &uTime
}
mongoLocalTime := GetNowTimestamp()
var producerMessage = model.ProducerMessage{
Id: nacosUtils.GetUUID(),
MessagesId: "nvahfaijbidjfani234ndxkcna",
Message: "测试样例",
CreateTime: mongoLocalTime,
UpdateTime: mongoLocalTime,
}
// mongo的CRUD操作 ......
如上面的操作, 存取都不影响数据的结果, mongo中存储的时间数据样例为 :
"updateTime": ISODate("2023-09-08T06:36:55.234Z")
总结
我的建议是, 没事儿别用mongo, 除非你很有必要用, 没那么大业务量, 或者公司资金紧张就老实用MySQL吧, mongo这东西对硬件要求很高, 内存小了, 随便一个排序都报错.