Golang中如何将JSON日期字符串转为BSON日期插入MongoDB?
问题解决:将JSON中的UTC日期字符串转为MongoDB的BSON Date类型
一、bson.UnmarshalExtJSON第二个参数的作用
bson.UnmarshalExtJSON的第二个参数是布尔类型的isJSONArray,用来指定输入的JSON数据类型:
- 如果输入是单个JSON对象(比如你提供的示例),传
false - 如果输入是JSON数组(比如
[{}, {}, ...]这种多文档集合),传true
补充说明下容易混淆的第三个参数:它是UnmarshalExtJSONOptions配置项,其中的DateTime字段仅对Mongo扩展JSON格式的日期(即{"$date": "UTC字符串"}结构)生效,可指定将其解析为time.Time、字符串或时间戳,但你的输入是普通ISO日期字符串,所以这个选项对你的场景不适用。
二、实现日期转BSON Date的正确方式
由于你不能修改输入JSON,也无法手动定义文档结构体,我们可以先把JSON解析为bson.M(动态键值对结构),再递归遍历所有字段,把符合UTC ISO格式的字符串转为time.Time类型(MongoDB会自动将time.Time序列化为BSON Date)。
完整代码示例:
package main import ( "time" "go.mongodb.org/mongo-driver/bson" ) func main() { // 你的输入JSON数据 jsonData := []byte(`{ "name": "Lex", "dob": "2022-11-01T06:30:30.639326208Z" }`) // 解析为bson.M var doc bson.M opts := bson.UnmarshalExtJSONOptions{} err := bson.UnmarshalExtJSON(jsonData, false, &doc, opts) if err != nil { panic(err) } // 递归转换所有符合格式的日期字符串 if err := convertDateStringsToTime(doc); err != nil { panic(err) } // 此时doc中的dob已经是time.Time类型,直接插入MongoDB即可 // 后续插入代码略... } // convertDateStringsToTime 递归遍历bson.M,将UTC ISO格式的字符串转为time.Time func convertDateStringsToTime(m bson.M) error { for key, val := range m { switch v := val.(type) { case string: // 尝试用RFC3339Nano格式解析(兼容高精度时间) if t, err := time.Parse(time.RFC3339Nano, v); err == nil { m[key] = t } case bson.M: // 递归处理嵌套文档 if err := convertDateStringsToTime(v); err != nil { return err } case []interface{}: // 处理数组中的元素 for i, elem := range v { if subDoc, ok := elem.(bson.M); ok { if err := convertDateStringsToTime(subDoc); err != nil { return err } } else if str, ok := elem.(string); ok { if t, err := time.Parse(time.RFC3339Nano, str); err == nil { v[i] = t } } } } } return nil }
方案说明
- 无需提前知晓文档结构,自动处理任意层级的嵌套文档和数组
- 仅转换符合
RFC3339Nano格式的UTC日期字符串,不会误修改其他字符串字段 - 转换后的
time.Time类型插入MongoDB时,会被自动序列化为BSON Date类型(存储为毫秒级时间戳)
内容的提问来源于stack exchange,提问作者BeetleJuice
相关产品推荐
相关产品推荐

