处理BSON
概述
在本指南中,您可以了解Go驱动程序如何处理BSON和Go类型之间的转换。将Go类型转换为BSON的过程称为序列化,而相反的过程称为反序列化。
以下各节解释了Go驱动程序如何表示BSON数据以及如何调整默认的序列化和反序列化行为。
数据类型
MongoDB以二进制形式存储文档,称为BSON,它允许轻松灵活地处理数据。
Go驱动程序为处理BSON数据提供了四种主要类型
D
:BSON文档的有序表示(切片)M
:BSON文档的无序表示(映射)A
:BSON数组的有序表示E
:D类型中的一个单一元素
以下示例演示了如何使用bson.D
类型构建查询过滤器,以匹配值为大于100的文档中的quantity
字段
filter := bson.D{{"quantity", bson.D{{"$gt", 100}}}}
要了解Go驱动程序如何处理BSON数据,请参阅bson包API文档。
结构体标签
在Go中,struct 是由声明的数据类型组成的字段集合。您可以通过使用 struct 标签 来修改 struct 字段的默认序列化和反序列化行为,struct 标签是附加到 struct 字段上的可选元数据。struct 标签最常见的使用是指定与 struct 字段相对应的 BSON 文档中的字段名称。以下表格描述了在 Go 驱动程序中可以使用的附加 struct 标签
Struct 标签 | 描述 |
---|---|
omitempty | 如果字段设置为与字段类型对应的零值,则不会对其进行序列化。 |
minsize | 如果字段类型为 int64 、uint 、uint32 或 uint64 ,并且字段的值可以适合有符号 int32 ,则该字段将序列化为 BSON int32 而不是 BSON int64 。如果值无法适合有符号 int32 ,则忽略此标签。 |
truncate | 如果字段类型为非浮点数值类型,则将反序列化到该字段的 BSON 双精度浮点数截断到小数点。 |
inline | 如果字段类型为 struct 或 map 字段,则字段在序列化时将扁平化,在反序列化时将取消扁平化。 |
如果您未指定 struct 标签,Go 驱动程序将根据以下规则序列化 struct
驱动程序仅序列化和反序列化导出字段。
驱动程序使用对应 struct 字段的字母小写来生成 BSON 键。
驱动程序将内嵌的 struct 字段序列化为子文档。每个键是该字段类型的字母小写。
如果指针非空,驱动程序将指针字段序列化为基础类型。如果指针为空,驱动程序将其序列化为 BSON null 值。
在反序列化时,Go 驱动程序遵循 这些 D/M 类型映射 来处理类型为
interface{}
的字段。驱动程序将反序列化到interface{}
字段的 BSON 文档作为D
类型。
以下示例演示了 Go 驱动程序如何序列化具有各种 struct 标签的 struct
type Address struct { Street string City string State string } type Student struct { FirstName string `bson:"first_name,omitempty"` LastName string `bson:"last_name,omitempty"` Address Address `bson:"inline"` Age int } coll := client.Database("db").Collection("students") address1 := Address{ "1 Lakewood Way", "Elwood City", "PA" } student1 := Student{ FirstName : "Arthur", Address : address1, Age : 8} _, err = coll.InsertOne(context.TODO(), student1)
相应的 BSON 表示形式如下
{ "_id" : ObjectId("..."), "first_name" : "Arthur", "street" : "1 Lakewood Way", "city" : "Elwood City", "state" : "PA", "age" : 8 }
在这个示例中,结构体标签使驱动程序
设置自定义的BSON字段名,例如
first_name
省略空的
LastName
字段将嵌套的结构体扁平化,并将所有字段提升到顶级
以下示例演示了Go驱动程序如何对没有结构体标签的结构体进行序列化
type Address struct { Street string City string State string } type Student struct { FirstName string LastName string Address Address Age int } coll := client.Database("db").Collection("students") address1 := Address{ "1 Lakewood Way", "Elwood City", "PA" } student1 := Student{ FirstName : "Arthur", Address : address1, Age : 8} _, err = coll.InsertOne(context.TODO(), student1)
相应的 BSON 表示形式如下
{ "_id" : ObjectId("..."), "firstname" : "Arthur", "lastname" : "", "address": { "street" : "1 Lakewood Way", "city" : "Elwood City", "state" : "PA" }, "age" : 8 }
没有结构体标签,驱动程序
将结构体字段的下划线形式作为BSON字段名
包括一个空的
lastname
字段将
Address
字段作为嵌套值存储
BSON 选项
您可以通过指定BSON选项来调整您的 Client
实例的序列化和反序列化行为。要在您的 Client
上设置BSON选项,创建并配置一个 BSONOptions
实例。
此示例执行以下操作
通过配置以下设置创建一个
BSONOptions
实例将
UseJSONStructTags
字段设置为true
,这指示驱动程序在未指定"bson"
结构体标签的情况下使用"json"
结构体标签将
NilSliceAsEmpty
字段设置为true
,这指示驱动程序将nil
Go 切片序列化为空的BSON数组
将
BSONOptions
实例传递给SetBSONOptions()
辅助方法以指定ClientOptions
实例创建一个
Client
以应用指定的BSON序列化和反序列化行为
bsonOpts := &options.BSONOptions { UseJSONStructTags: true, NilSliceAsEmpty: true, } clientOpts := options.Client(). ApplyURI("<connection string>"). SetBSONOptions(bsonOpts) client, err := mongo.Connect(context.TODO(), clientOpts)
提示
要了解更多关于 BSONOptions
类型的信息,请参阅BSONOptions API 文档。要查看指定 BSONOptions
实例并使用这些选项创建客户端的示例,请参阅Connect() BSONOptions 示例。
反序列化
您可以使用 FindOne
方法的结果或任何 *mongo.Cursor
实例上的 Decode()
方法来反序列化 BSON 文档。
Decode()
方法返回一个包含以下值的 error
类型:
nil
如果文档与您的查询匹配,并且检索和反序列化文档时没有错误。如果驱动程序检索了您的文档但无法反序列化您的结果,则
Decode()
方法返回反序列化错误。如果在执行
FindOne()
方法时检索文档出现错误,则该错误会传播到Decode()
方法,并且Decode()
方法会返回错误。
当在由FindOne()
方法返回的SingleResult
类型上使用时,如果查询过滤器没有匹配到文档,Decode()
也可以返回ErrNoDocuments
错误。
以下示例演示了如何使用Decode()
方法来反序列化和读取简单的FindOne()
操作的结果
coll := client.Database("db").Collection("students") filter := bson.D{{"age", 8}} var result bson.D err := coll.FindOne(context.TODO(), filter).Decode(&result) fmt.Println(result)
[{_id ObjectID("...")} {first_name Arthur} {street 1 Fern Way} {city Elwood City} {state PA} {age 8}]
Cursor
类型也使用All()
方法,该方法将游标中存储的所有文档同时反序列化到数组中。
bson
包包括一系列与[]byte
类型BSON编码数据一起工作的Marshal()
和Unmarshal()
方法。
以下代码演示了如何使用bson
包中的方法将BSON反序列化回用户定义的结构体
type Item struct { Category string Quantity int32 } doc, err := bson.Marshal(bson.D{{"category", "plate"}, {"quantity", 6}}) var test Item err = bson.Unmarshal(doc, &test) fmt.Printf("Unmarshalled Struct:\n%+v\n", test)
Unmarshalled Struct: {Category:plate Quantity:6}
注意
您可以使用Raw
类型从BSON文档字节数组中检索元素,而无需将其反序列化到Go类型。此类型允许您在不反序列化整个BSON文档的情况下查找单个元素。
有关与Cursor
类型一起使用的序列化和反序列化方法的更多信息,请参阅Cursor API文档
有关bson
包中序列化和反序列化方法的更多信息,请参阅bson API文档