文档菜单
文档首页
/ / /
C++ 驱动程序
/

与 BSON 合作

本页内容

  • 文档构建器
  • 列表构建器
  • "一次性"构建函数
  • 基本构建器
  • 循环中构建数组
  • 拥有 BSON 文档
  • 非拥有 BSON 文档(视图)
  • 可选拥有 BSON 文档(view_or_value)
  • BSON 文档生命周期
  • 打印 BSON 文档
  • 从 BSON 文档中获取字段
  • BSON 类型

mongocxx 驱动程序附带一个新的库,bsoncxx。本文将介绍该库中的一些不同类型,以及何时以及如何使用每个类型。有关更多信息,请参阅我们的示例.

  1. 文档构建器

  2. 拥有 BSON 文档(值)

  3. 非拥有 BSON 文档(视图)

  4. 可选拥有 BSON 文档(view_or_value)

  5. BSON 文档生命周期

  6. 打印 BSON 文档

  7. 从 BSON 文档中获取字段

  8. BSON 类型

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;
}

bsoncxx::document::value

此类型表示实际的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;

bsoncxx::document::view

此类型是针对所有者 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());

许多驱动程序方法都接受一个 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 类型还有助于缓解下一节中讨论的一些生命周期问题。

必须保证 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!!

bsoncxx::to_json()

bsoncxx 库附带一个便利方法,将 BSON 文档转换为字符串以方便检查

bsoncxx::document::value = document{} << "I am" << "a BSON document" << finalize;
std::cout << bsoncxx::to_json(doc.view()) << std::endl;

存在一个类似的方法,from_json(),用于从现有的 JSON 字符串构建 document::values。

方括号操作符 [ ] 可以进入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 规范》提供支持的类型列表。这些类型在 C++ 中使用 b_xxx 类型封装器表示。

一些 BSON 类型不一定有原生表示形式,而是通过特殊类实现。

bsoncxx::decimal128 类表示一个 128 位的 IEEE 754-2008 十进制浮点值。我们期望用户将这些值转换为字符串,反之亦然,但如果用户需要将其转换为本地 decimal128 类型,则提供对高 64 位和低 64 位值的访问。

您可以在这个示例中看到如何使用 bsoncxx::decimal128

返回

时间序列数据