【Golang】mongo对于时间序列化MarshalBSON和UnmarshalBSON

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这东西对硬件要求很高, 内存小了, 随便一个排序都报错.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值