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 驱动程序中使用的其他结构体标记:
结构标记 | 说明 |
|---|---|
| The field will not be marshaled if it is set to the zero value corresponding to the field type. To globally prevent the driver from marshaling fields set to a zero value, you can set the |
| 如果该字段的类型为 |
| 如果字段类型是非浮点数字类型, 则解组到该字段中的 BSON double 将在小数点处截断。 |
| 如果字段类型是结构或映射字段,则字段在编组时将扁平化, 而在解组时将取消扁平化。 |
如果您不指定结构体标记,则 Go 驱动程序将使用以下规则编组结构体:
驱动程序仅编组和解组已导出的字段。
驱动程序使用相应结构体字段的小写字母生成 BSON 密钥。
此驱动程序会将嵌入的结构字段封送为子文档。每个键 均为该字段的小写类型表示法。
如果指针不为 nil,则驱动程序会将指针字段作为底层类型。 如果指针为 nil,则驱动程序将其编组为 BSON null 值。
When unmarshalling, the Go driver follows these D/M type mappings for fields of type
any. The driver unmarshals BSON documents unmarshalled into ananyfield as aDtype.
BSON 选项
可以指定 BSON 选项来调整 Client 实例的编组和解组行为。要在 Client 上设置 BSON 选项,请创建并配置 BSONOptions 实例。
此示例将执行以下动作:
通过配置以下设置来创建
BSONOptions实例:将
UseJSONStructTags字段设置为true,这指示驱动程序在未指定"bson"结构标记的情况下使用"json"结构标记将
NilSliceAsEmpty字段设置为true,指示驱动程序将nilGo 切片编组为空 BSON 数组将
OmitEmpty字段设置为true,指示驱动程序全局省略编组 BSON 中的空值,而不是将空值设置为null
将
BSONOptions实例传递给SetBSONOptions()辅助方法,以指定ClientOptions实例创建
Client以应用指定的 BSON 封送和拆收行为
bsonOpts := &options.BSONOptions { UseJSONStructTags: true, NilSliceAsEmpty: true, OmitEmpty: true, } clientOpts := options.Client(). ApplyURI("<connection string>"). SetBSONOptions(bsonOpts) client, err := mongo.Connect(clientOpts)
提示
To learn more about the BSONOptions type, see the BSONOptions API documentation. For an example that specifies a BSONOptions instance and creates a client with these options, see the Connect() BSONOptions example.
解组
您可以对 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)
此外,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)
注意
您可以使用 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)
要学习;了解有关 Raw 类型系列的详情,请参阅原始BSON API文档。