使用 mongodb go 驱动程序将文档解码为具有自定义类型字段的结构
Using mongodb go driver for decoding documents into structs with custom type fields
我是 go 和 mongodb 的初学者。
我尝试使用 bson 标记将 DocumentResult
解码为结构,但它不适用于包装字符串的自定义类型。
不把字段的类型改成字符串能做到吗?
import (
"context"
"github.com/mongodb/mongo-go-driver/mongo"
)
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType MyType `bson:"custom_type,omitempty"`
}
type MyType string
const myType MyType = "ABCD"
func main() {
//Connect to db
client, _ := mongo.Connect(context.Background(), "mongodb://localhost:27017", nil)
db := client.Database("example_db")
collection := db.Collection("col")
//Insert document
docToInsert := MyDoc{42, "The Answer", myType}
collection.InsertOne(nil, docToInsert)
//Retrieve document
filterDoc := MyDoc{SomeInt: 42}
resultDoc := &MyDoc{}
result := collection.FindOne(nil, filterDoc)
result.Decode(resultDoc)
println(resultDoc.SomeInt, resultDoc.SomeString, resultDoc.CustomType)
PRINTED RESULT: "42 The Answer" //"ABCD" is missing
提前致谢
前言: 具有 string
作为其基础类型的自定义类型现在由驱动程序自动处理。此答案早于驱动程序 1.x
版本,这是必要的。
不幸的是你运气不好。官方 mongo go 驱动程序的当前状态不支持将 string
值从 BSON 解组为 Go 值,其类型是具有 string
作为其基础类型的自定义类型。这在未来可能会改变,但目前不支持。
在 bson/decode.go
, currently line #387:
中实现了解码为结构字段的处理方式
case 0x2:
str := v.StringValue()
switch containerType {
case tString, tEmpty:
val = reflect.ValueOf(str)
case tJSONNumber:
_, err := strconv.ParseFloat(str, 64)
if err != nil {
return val, err
}
val = reflect.ValueOf(str).Convert(tJSONNumber)
case tURL:
u, err := url.Parse(str)
if err != nil {
return val, err
}
val = reflect.ValueOf(u).Elem()
default:
return val, nil
}
0x02
是 BSON 字符串类型。如果结构字段的类型是以下任何一种,它只会尝试解码到结构字段中:string
、interface{}
、json.Number
or url.URL
(或指向这些的指针)。
不幸地实现了 bson.Unmarshaler
on your custom type does not help either, as it is not checked in case of struct fields, only if the struct itself implements it. But implementing on the struct itself, you would have to duplicate the struct with the field being one of the above listed supported types (or use a map or a bson.Document
类型)。
这是库的一个严重限制,很容易解决,所以我们希望他们能在不久的将来增加对此的支持。
I try to decode a DocumentResult into a struct using bson tags, and it does not work for a custom type wrapping a string
使用您当前的 MyType
,将存储在 MongoDB 中的文档如下所示:
{
"_id": ObjectId("..."),
"some_int": NumberLong("42"),
"some_string": "The Answer",
"custom_type": "ABCD"
}
即使基础类型是 string
,由于类型包装,使用当前版本的 mongo-go-driver (v0.0.12) 解码可能会很棘手。
但是,如果您想要这样的自定义类型,您可以将结构更改为 an embedded field。例如:
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType MyType `bson:"custom_type,omitempty"`
}
type MyType struct {
Value string `bson:"value,omitempty"`
}
var myType = MyType{Value: "ABCD"}
docToInsert := MyDoc{42, "The Answer", "ABCD"}
insertResult, err := collection.InsertOne(nil, docToInsert)
resultDoc := collection.FindOne(context.Background(), nil)
if err != nil {
log.Fatal(err)
}
elem := &MyDoc{}
err = resultDoc.Decode(elem)
if err != nil {
log.Fatal(err)
}
fmt.Println(elem.SomeInt, elem.SomeString, elem.CustomType.Value)
// 42 The Answer ABCD
文档将存储在 MongoDB 中,如下所示:
{
"_id": ObjectId("..."),
"some_int": NumberLong("42"),
"some_string": "The Answer",
"custom_type": {
"value": "ABCD"
}
}
否则直接使用 string
类型,因为数据库中生成的文档将与类型包装版本相同:
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType string `bson:"custom_type,omitempty"`
}
您可能还会发现 MongoDB Data Modeling 是有用的参考。
使用 1.x 版本的 MongoDB Go 驱动程序(撰写本文时的最新版本是 1.3.1),完全可以编码和解码别名类型。
您的示例现在可以按预期运行,假设调整 mongo.Connect
以匹配新的 1.x
API。
package main
import (
"context"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType MyType `bson:"custom_type,omitempty"`
}
type MyType string
const myType MyType = "ABCD"
func main() {
// Connect to db
clientOpts := options.Client().
ApplyURI("mongodb://localhost/example_db")
client, _ := mongo.Connect(context.Background(), clientOpts)
db := client.Database("example_db")
collection := db.Collection("col")
// Insert document
docToInsert := MyDoc{42, "The Answer", myType}
collection.InsertOne(nil, docToInsert)
// Retrieve document
filterDoc := MyDoc{SomeInt: 42}
resultDoc := &MyDoc{}
result := collection.FindOne(nil, filterDoc)
result.Decode(resultDoc)
println(resultDoc.SomeInt, resultDoc.SomeString, resultDoc.CustomType)
}
这 returns:42 The Answer ABCD
符合预期
我是 go 和 mongodb 的初学者。
我尝试使用 bson 标记将 DocumentResult
解码为结构,但它不适用于包装字符串的自定义类型。
不把字段的类型改成字符串能做到吗?
import (
"context"
"github.com/mongodb/mongo-go-driver/mongo"
)
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType MyType `bson:"custom_type,omitempty"`
}
type MyType string
const myType MyType = "ABCD"
func main() {
//Connect to db
client, _ := mongo.Connect(context.Background(), "mongodb://localhost:27017", nil)
db := client.Database("example_db")
collection := db.Collection("col")
//Insert document
docToInsert := MyDoc{42, "The Answer", myType}
collection.InsertOne(nil, docToInsert)
//Retrieve document
filterDoc := MyDoc{SomeInt: 42}
resultDoc := &MyDoc{}
result := collection.FindOne(nil, filterDoc)
result.Decode(resultDoc)
println(resultDoc.SomeInt, resultDoc.SomeString, resultDoc.CustomType)
PRINTED RESULT: "42 The Answer" //"ABCD" is missing
提前致谢
前言: 具有 string
作为其基础类型的自定义类型现在由驱动程序自动处理。此答案早于驱动程序 1.x
版本,这是必要的。
不幸的是你运气不好。官方 mongo go 驱动程序的当前状态不支持将 string
值从 BSON 解组为 Go 值,其类型是具有 string
作为其基础类型的自定义类型。这在未来可能会改变,但目前不支持。
在 bson/decode.go
, currently line #387:
case 0x2:
str := v.StringValue()
switch containerType {
case tString, tEmpty:
val = reflect.ValueOf(str)
case tJSONNumber:
_, err := strconv.ParseFloat(str, 64)
if err != nil {
return val, err
}
val = reflect.ValueOf(str).Convert(tJSONNumber)
case tURL:
u, err := url.Parse(str)
if err != nil {
return val, err
}
val = reflect.ValueOf(u).Elem()
default:
return val, nil
}
0x02
是 BSON 字符串类型。如果结构字段的类型是以下任何一种,它只会尝试解码到结构字段中:string
、interface{}
、json.Number
or url.URL
(或指向这些的指针)。
不幸地实现了 bson.Unmarshaler
on your custom type does not help either, as it is not checked in case of struct fields, only if the struct itself implements it. But implementing on the struct itself, you would have to duplicate the struct with the field being one of the above listed supported types (or use a map or a bson.Document
类型)。
这是库的一个严重限制,很容易解决,所以我们希望他们能在不久的将来增加对此的支持。
I try to decode a DocumentResult into a struct using bson tags, and it does not work for a custom type wrapping a string
使用您当前的 MyType
,将存储在 MongoDB 中的文档如下所示:
{
"_id": ObjectId("..."),
"some_int": NumberLong("42"),
"some_string": "The Answer",
"custom_type": "ABCD"
}
即使基础类型是 string
,由于类型包装,使用当前版本的 mongo-go-driver (v0.0.12) 解码可能会很棘手。
但是,如果您想要这样的自定义类型,您可以将结构更改为 an embedded field。例如:
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType MyType `bson:"custom_type,omitempty"`
}
type MyType struct {
Value string `bson:"value,omitempty"`
}
var myType = MyType{Value: "ABCD"}
docToInsert := MyDoc{42, "The Answer", "ABCD"}
insertResult, err := collection.InsertOne(nil, docToInsert)
resultDoc := collection.FindOne(context.Background(), nil)
if err != nil {
log.Fatal(err)
}
elem := &MyDoc{}
err = resultDoc.Decode(elem)
if err != nil {
log.Fatal(err)
}
fmt.Println(elem.SomeInt, elem.SomeString, elem.CustomType.Value)
// 42 The Answer ABCD
文档将存储在 MongoDB 中,如下所示:
{
"_id": ObjectId("..."),
"some_int": NumberLong("42"),
"some_string": "The Answer",
"custom_type": {
"value": "ABCD"
}
}
否则直接使用 string
类型,因为数据库中生成的文档将与类型包装版本相同:
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType string `bson:"custom_type,omitempty"`
}
您可能还会发现 MongoDB Data Modeling 是有用的参考。
使用 1.x 版本的 MongoDB Go 驱动程序(撰写本文时的最新版本是 1.3.1),完全可以编码和解码别名类型。
您的示例现在可以按预期运行,假设调整 mongo.Connect
以匹配新的 1.x
API。
package main
import (
"context"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type MyDoc struct {
SomeInt int `bson:"some_int"`
SomeString string `bson:"some_string,omitempty"`
CustomType MyType `bson:"custom_type,omitempty"`
}
type MyType string
const myType MyType = "ABCD"
func main() {
// Connect to db
clientOpts := options.Client().
ApplyURI("mongodb://localhost/example_db")
client, _ := mongo.Connect(context.Background(), clientOpts)
db := client.Database("example_db")
collection := db.Collection("col")
// Insert document
docToInsert := MyDoc{42, "The Answer", myType}
collection.InsertOne(nil, docToInsert)
// Retrieve document
filterDoc := MyDoc{SomeInt: 42}
resultDoc := &MyDoc{}
result := collection.FindOne(nil, filterDoc)
result.Decode(resultDoc)
println(resultDoc.SomeInt, resultDoc.SomeString, resultDoc.CustomType)
}
这 returns:42 The Answer ABCD
符合预期