如何使用MongoDB Go驱动将BSON Double转换为time.Time类型?
解决MongoDB Go驱动解码Double毫秒时间戳到time.Time的问题
MongoDB Go驱动v1.16.0没有内置配置直接处理这种混合类型的日期字段,但可以通过自定义BSON解码器实现兼容,同时支持标准BSON日期和Double类型的毫秒时间戳解码到time.Time字段。
实现步骤
- 编写自定义解码函数,判断字段的BSON类型:
- 若为BSON日期类型,直接解码为
time.Time - 若为BSON Double类型,先转换为int64毫秒数,再转为
time.Time
- 若为BSON日期类型,直接解码为
- 将解码器注册到驱动的
bsoncodec.Registry中 - 连接数据库时使用该自定义Registry
完整代码示例
package main import ( "context" "fmt" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/bson/bsonrw" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type Dummy struct { Id int `bson:"_id"` CreatedDate *time.Time `bson:"createdDate"` } // 自定义time.Time解码器,兼容BSON日期和Double毫秒时间戳 func customTimeDecoder(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val bsoncodec.Value) error { switch vr.Type() { case bson.TypeDateTime: // 处理标准BSON日期 dt, err := vr.ReadDateTime() if err != nil { return err } t := time.UnixMilli(dt) *val.Interface().(*time.Time) = t return nil case bson.TypeDouble: // 处理Double类型的毫秒时间戳 ms, err := vr.ReadDouble() if err != nil { return err } t := time.UnixMilli(int64(ms)) *val.Interface().(*time.Time) = t return nil default: return fmt.Errorf("cannot decode %v into time.Time", vr.Type()) } } func main() { // 创建自定义Registry registry := bson.NewRegistry() // 注册自定义time.Time解码器 registry.RegisterTypeDecoder( bson.TypeDateTime, bsoncodec.ValueDecoderFunc(customTimeDecoder), ) // 注册Double类型到time.Time的解码逻辑 registry.RegisterTypeDecoder( bson.TypeDouble, bsoncodec.ValueDecoderFunc(customTimeDecoder), ) // 连接数据库时指定自定义Registry clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetRegistry(registry) client, err := mongo.Connect(context.TODO(), clientOpts) if err != nil { panic(err) } defer client.Disconnect(context.TODO()) // 测试查询 coll := client.Database("test").Collection("dummy") var result Dummy err = coll.FindOne(context.TODO(), bson.M{"_id": 1}).Decode(&result) if err != nil { panic(err) } fmt.Printf("ID: %d, CreatedDate: %v\n", result.Id, result.CreatedDate) }
关键说明
- 自定义解码器会先识别字段的BSON类型,分别处理两种格式的日期数据
- 必须同时注册
bson.TypeDateTime和bson.TypeDouble到time.Time的解码逻辑,才能覆盖两种场景 - 连接客户端时通过
SetRegistry传入自定义Registry,驱动就会使用我们的解码规则处理数据
这样就能同时兼容两种格式的createdDate字段,解决解码报错问题。
内容的提问来源于stack exchange,提问作者takanuva15
相关产品推荐
相关产品推荐

