Overview
在本指南中,你可以了解 Go 驱动程序如何处理 BSON 和 Go 类型之间的转换。将 GO 类型转换为 BSON 的过程称为编组,反之称为解组。
以下部分解释 Go 驱动程序如何表示 BSON 数据 以及您如何调整默认编组和解组行为。
数据类型
MongoDB 采用名为 BSON 的二进制表示形式存储文档,可以轻松灵活地进行数据处理。
Go 驱动程序提供了四类主要驱动程序来处理 BSON 数据:
D
:BSON 文档的有序表示(切片)M
:BSON 文档的无序表示(映射)A
:BSON 数组的有序表示形式E
:D 类型内部的单个元素
以下示例演示如何使用 bson.D
类型构造查询筛选器,匹配其中 quantity
字段值大于 100 的文档:
filter := bson.D{{"quantity", bson.D{{"$gt", 100}}}}
如需进一步了解 Go 驱动程序如何处理 BSON 数据,请参阅 bson 程序包 API 文档。
结构体标记
在 Go 中,结构体是具有声明数据类型的数据字段的集合。您可以使用结构体标记修改结构体字段的默认编组和解组行为,结构体标记是附加到结构体字段的可选元数据片段。结构体标记最常见的用途是指定 BSON 文档中与结构体字段对应的字段名称。下表给出可以在 Go 驱动程序中使用的其他结构体标记:
结构标记 | 说明 |
---|---|
| 如果字段设置为与字段类型对应的零值,则不会对字段编组。 |
| 如果该字段的类型为 |
| 如果字段类型是非浮点数字类型, 则解组到该字段中的 BSON double 将在小数点处截断。 |
| 如果字段类型是结构或映射字段,则字段在编组时将扁平化, 而在解组时将取消扁平化。 |
如果您不指定结构体标记,则 Go 驱动程序将使用以下规则编组结构体:
驱动程序仅编组和解组已导出的字段。
驱动程序使用相应结构体字段的小写字母生成 BSON 密钥。
此驱动程序会将嵌入的结构字段封送为子文档。每个键 均为该字段的小写类型表示法。
如果指针不为 nil,则驱动程序会将指针字段作为底层类型。 如果指针为 nil,则驱动程序将其编组为 BSON null 值。
解组时,Go 驱动程序会针对
interface{}
类型的字段遵循这些 D/M 类型映射。驱动程序将 BSON 文档解组为D
类型,解组到interface{}
字段中。
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(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
包包含一系列 Marshal()
和 Unmarshal()
方法,这些方法可处理 []byte
类型的BSON编码数据。bson.Marshal()
和 bson.Unmarshal()
方法需要一个可以编码到BSON文档中的参数,例如 bson.D
类型。如果传递的类型不正确,则会发生 Write
错误。示例,如果将字符串传递给 bson.Marshal()
,则会发生 WriteString
错误。
以下代码演示如何使用 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文档。有关如何使用 Raw
类型的更多信息,请参阅“使用原始BSON数据”部分。
要详细学习;了解用于 Cursor
类型的编组和解组方法,请参阅 Cursor API文档。
要学习;了解有关 bson
包中编组和解组方法的详情,请参阅BSON API文档。
使用原始BSON数据
Go驾驶员支持通过 Raw
类型处理原始BSON文档。Raw
类型允许您验证和检索字节切片中的元素,而无需解组整个BSON文档。这在以下情况下非常有用:
在不转换整个文档的情况下对特定字段执行查找
通过避免完整文档解组来减少内存开销
直接处理从数据库收到的二进制BSON数据
Raw
类型提供了验证BSON文档和通过键查找各个元素的方法。以下示例演示了如何验证原始BSON文档并从中检索特定字段:
collection := client.Database("sample_restaurants").Collection("restaurants") findOptions := options.FindOne() var raw bson.Raw err = collection.FindOne( context.TODO(), bson.D{{"name", "Mongo's Pizza"}}, findOptions, ).Decode(&raw) if err != nil { log.Fatalf("Failed to find document: %v", err) } // Print the document type fmt.Printf("Document type: %T\n", raw) // Access a field from the raw document name := raw.Lookup("name").StringValue() fmt.Println("Restaurant name:", name)
Document type: bson.Raw Restaurant name: Mongo's Pizza
要学习;了解有关 Raw
类型系列的详情,请参阅原始BSON API文档。