使用 BSON
在此页面上
mongocxx驾驶员附带一个新的库 bsoncxx。 Go本文将Go此库中的一些不同类型,以及如何以及何时使用每种类型。有关更多信息和示例代码,请参阅我们的 示例。
文档生成器
bsoncxx 库提供了四个用于构建 BSON 的接口:一次性函数、基本构建器、列表构建器和基于流的构建器。
bsoncxx::builder::basic::document bsoncxx::builder::stream::document
创建 BSON 文档和数组的各种方法都是等效的。 所有接口都将提供相同的结果,使用哪个接口的选择完全取决于美观。
列表生成器
创建 BSON 文档或数组的最简单方法是使用类似 JSON 的列表构建器:
// { "hello": "world" } bsoncxx::builder::list list_builder = {"hello", "world"}; bsoncxx::document::view document = list_builder.view().get_document();
“一次性”构建器函数
“一次性”构建器在单次调用中创建文档和数组。 当不需要使用其他逻辑(例如条件或循环)来创建对象时,可以使用这些对象:
using bsoncxx::builder::basic::kvp; // { "hello": "world" } bsoncxx::document::value document = bsoncxx::builder::basic::make_document(kvp("hello", "world"));
基本生成器
using bsoncxx::builder::basic::kvp; // { "hello" : "world" } bsoncxx::builder::basic::document basic_builder{}; basic_builder.append(kvp("hello", "world")); bsoncxx::document::value document = basic_builder.extract();
// { "hello" : "world" } using bsoncxx::builder::stream; bsoncxx::document::value document = stream::document{} << "hello" << "world" << stream::finalize;
注意
为了正确附加每个新值,流构建器需要跟踪当前文档的状态,包括嵌套级别和附加到构建器的最新值的类型。 在此状态更改后,不得重复使用初始流构建器,这意味着如果使用流构建器跨多个语句构建文档,则必须将中间值存储在新变量中。 由于正确执行此操作很困难,并且编译器错误消息可能会令人困惑,因此不鼓励使用流构建器。 我们建议改用基本构建器或一次性构建器函数。
在循环中构建数组
有时需要使用循环来构建数组。 使用基本构建器,只需在循环内调用 append
即可构建顶层数组:
// [ 1, 2, 3 ] const auto elements = {1, 2, 3}; auto array_builder = bsoncxx::builder::basic::array{}; for (const auto& element : elements) { array_builder.append(element); }
要在循环中构建子数组,请将Lambda传递给 append
(如果子数组包含在文档而不是数组中,则作为 kvp
的第二个参数):
// { "foo" : [ 1, 2, 3 ] } using bsoncxx::builder::basic::kvp; using bsoncxx::builder::basic::sub_array; const auto elements = {1, 2, 3}; auto doc = bsoncxx::builder::basic::document{}; doc.append(kvp("foo", [&elements](sub_array child) { for (const auto& element : elements) { child.append(element); } }));
使用流构建器构建数组时,请务必注意在流构建器上使用<<
操作符的返回类型并不统一。 要在循环中正确构建数组,当类型更改时,应将流构建器返回的中间值存储在变量中。 使用循环从流构建器构建数组的一次尝试可能如下所示:
// { "subdocs" : [ { "key" : 1 }, { "key" : 2 }, { "key" : 3 } ], "another_key" : 42 } using namespace bsoncxx; builder::stream::document builder{}; auto in_array = builder << "subdocs" << builder::stream::open_array; for (auto&& e : {1, 2, 3}) { in_array = in_array << builder::stream::open_document << "key" << e << builder::stream::close_document; } auto after_array = in_array << builder::stream::close_array; after_array << "another_key" << 42; document::value doc = after_array << builder::stream::finalize; std::cout << to_json(doc) << std::endl;
注意
任何流操作的结果都应该被捕获,因此,如果您想将上述 for 循环中的单个语句拆分为多个语句,则必须捕获每个中间结果。 此外,循环体内的最后一条语句应将其结果赋回 in_array 对象,以便循环以一致的状态重新启动:
for (auto && e : {1, 2, 3}) { auto open_state = in_array << builder::stream::open_document; auto temp_state = open_state << "key" << e; in_array = temp_state << builder::stream::close_document; }
拥有 BSON 文档
该类型表示实际的 BSON 文档,即拥有数据缓冲区的文档。 可以通过调用extract()
从构建器构建这些文档:
bsoncxx::document::value basic_doc{basic_builder.extract()}; bsoncxx::document::value stream_doc{stream_builder.extract()};
调用extract()
后,该构建器处于移出状态,不应使用。
可以使用流构建器接口和finalize
令牌在一行中创建bsoncxx::document::value
。 finalize
从临时流构建器返回document::value
:
// { "finalize" : "is nifty" } bsoncxx::document::value one_line = bsoncxx::builder::stream::document{} << "finalize" << "is nifty" << bsoncxx::builder::stream::finalize;
非拥有 BSON 文档(视图)
该类型是所属bsoncxx::document::value
的视图。
bsoncxx::document::view document_view{document_value.view()};
document::value
也会隐式转换为document::view
:
bsoncxx::document::view document_view{document_value};
在性能关键型代码中,传递视图比使用值更可取,因为可以避免过多的复制。 此外,通过传递文档视图,我们还可以多次使用该文档:
// { "copies" : { "$gt" : 100 } } auto query_value = document{} << "copies" << open_document << "$gt" << 100 << close_document << finalize; // Run the same query across different collections auto collection1 = db["science_fiction"]; auto cursor1 = collection1.find(query_value.view()); auto collection2 = db["cookbooks"]; auto cursor2 = collection2.find(query_value.view());
可选拥有的 BSON 文档 (view_or_value)
许多驾驶员方法都采用document::view_or_value
参数,示例 run_command:
bsoncxx::document::value run_command(bsoncxx::document::view_or_value command);
此类方法可以采用document::view
或document::value
。 如果传入document::value
,则必须通过右值引用传递,以便将文档的所有权转移给该方法。
document::value ping = document{} << "ping" << 1 << finalize; // You can pass a document::view into run_command() db.run_command(ping.view()); // Or you can move in a document::value db.run_command(std::move(ping));
您不需要为了使用驱动程序而直接创建view_or_value
类型。 它们是作为一种便捷方法提供的,允许驱动程序方法以拥有或非拥有的方式获取文档。 view_or_value
类型还有助于缓解下一节中讨论的一些生命周期问题。
BSON 文档生命周期
document::value
类型的寿命必须比使用它们的任何document::view
类型的寿命长。 如果底层值被清理,视图将留下一个悬空指针。 考虑一个返回新建文档视图的方法:
bsoncxx::document::view make_a_dangling_view() { bsoncxx::builder::basic::document builder{}; builder.append(kvp("hello", "world")); // This creates a document::value on the stack that will disappear when we return. bsoncxx::document::value stack_value{builder.extract()}; // We're returning a view of the local value return stack_value.view(); // Bad!! }
此方法会返回不应使用的悬空视图:
// This view contains a dangling pointer bsoncxx::document::view dangling_view = make_a_dangling_view(); // Warning!!
尝试通过构建器创建视图同样会创建危险的视图对象,因为不会捕获从extract()
返回的临时值:
bsoncxx::builder::stream::document temp_builder{}; temp_builder << "oh" << "no"; bsoncxx::document::view dangling_view = temp_builder.extract().view(); // Bad!!
打印 BSON 文档
bsoncxx 库提供了一种将 BSON 文档转换为字符串以便于检查的便捷方法:
bsoncxx::document::value = document{} << "I am" << "a BSON document" << finalize; std::cout << bsoncxx::to_json(doc.view()) << std::endl;
有一个类似的方法 from_json() ,从现有JSON字符串构建文档::values。
从 BSON 文档中获取字段
[ ] 操作符进入 BSON 文档以检索值:
// doc_view = { "store" : "Key Foods", "fruits" : [ "apple", "banana" ] } auto store = doc_view["store"]; auto first_fruit = doc_view["fruits"][0];
此操作会返回一个bsoncxx::document::element
,其中包含实际所需的值:
document::element store_ele{doc_view["store"]}; if (store_ele) { // this block will only execute if "store" was found in the document std::cout << "Examining inventory at " << to_json(store_ele.get_value()) << std::endl; }
BSON类型
BSON规范 提供了支持的类型列表。这些在C++中使用 b_xxx 表示 类型包装器。
某些BSON types不一定有要包装的原生表示形式,而是通过特殊类实现的。
Decimal128
bsoncxx::decimal128
类表示128位 IEEE 754 - 2008十进制浮点值。 我们希望用户能够将这些值与字符串相互转换,但如果用户需要转换为原生十进制128类型,则可以访问低位和高位64位值。
您可以在bsoncxx::decimal128
此示例 中了解如何使用 。