How to create and use BSON documents.
Create a Document
From a JSON String
Basic Example
void example() {
{
"a": 1,
"b": 2.0,
"c": "three"
}
)");
ASSERT(doc["a"].get_int32().value == 1);
ASSERT(doc["b"].get_double().value == 2.0);
ASSERT(doc[
"c"].get_string().
value.compare(
"three") == 0);
}
With Extended JSON
void example() {
{
"a": {"$numberInt": "1"},
"b": {"$numberLong": "2"},
"c": {"$numberDouble": "3"}
}
)");
ASSERT(doc["a"].get_int32().value == 1);
ASSERT(doc["b"].get_int64().value == 2);
ASSERT(doc["c"].get_double().value == 3.0);
}
With a Sub-Document
void example() {
{
"v": {"key": "value"}
}
)");
ASSERT(v[
"key"].get_string().
value.compare(
"value") == 0);
}
With a Sub-Array
void example() {
{
"v": [1, 2]
}
)");
ASSERT(sub[0].get_int32().value == 1);
ASSERT(sub[1].get_int32().value == 2);
}
With a User-Defined Literal
void example() {
ASSERT(a == b);
}
Using the Basic Builder
Basic Example
void example() {
builder.append(
kvp(
"a", std::int32_t{1}),
kvp(
"b", 2.0),
kvp(
"c",
"three"));
ASSERT(doc["a"].get_int32().value == 1);
ASSERT(doc["b"].get_double().value == 2.0);
ASSERT(doc[
"c"].get_string().
value.compare(
"three") == 0);
}
With make_document
void example() {
kvp(
"a", std::int32_t{1}),
kvp(
"b", 2.0),
kvp(
"c",
"three"));
ASSERT(doc["a"].get_int32().value == 1);
ASSERT(doc["b"].get_double().value == 2.0);
ASSERT(doc[
"c"].get_string().
value.compare(
"three") == 0);
}
With Multiple Appends
void example() {
builder.append(
kvp(
"a", std::int32_t{1}));
builder.append(
kvp(
"b", 2.0));
builder.append(
kvp(
"c",
"three"));
ASSERT(doc["a"].get_int32().value == 1);
ASSERT(doc["b"].get_double().value == 2.0);
ASSERT(doc[
"c"].get_string().
value.compare(
"three") == 0);
}
To Create Multiple Documents
void example() {
builder.append(
kvp(
"v", std::int32_t{1}));
builder.clear();
builder.append(
kvp(
"v", std::int64_t{2}));
ASSERT(a[
"v"].
type() == bsoncxx::type::k_int32);
ASSERT(b[
"v"].
type() == bsoncxx::type::k_int64);
ASSERT(a["v"].get_int32().value == 1);
ASSERT(b["v"].get_int64().value == 2);
}
With a Value Type
void example() {
kvp(
"a", std::int32_t{1}),
kvp(
"b", 2.0),
kvp(
"c",
"three"));
ASSERT(doc[
"a"].
type() == bsoncxx::type::k_int32);
ASSERT(doc[
"b"].
type() == bsoncxx::type::k_double);
ASSERT(doc[
"c"].
type() == bsoncxx::type::k_string);
ASSERT(doc["a"].get_int32().value == 1);
ASSERT(doc["b"].get_double().value == 2.0);
ASSERT(doc[
"c"].get_string().
value.compare(
"three") == 0);
}
With a BSON Type
void example() {
ASSERT(doc[
"a"].
type() == bsoncxx::type::k_int32);
ASSERT(doc[
"b"].
type() == bsoncxx::type::k_double);
ASSERT(doc[
"c"].
type() == bsoncxx::type::k_string);
ASSERT(doc["a"].get_int32() == a);
ASSERT(doc["b"].get_double() == b);
ASSERT(doc["c"].get_string() == c);
}
With a BSON Value
void example() {
std::int32_t{1},
2.0,
"three",
};
kvp(
"a", values[0]),
kvp(
"b", values[1]),
kvp(
"c", values[2]));
ASSERT(doc[
"a"].
type() == bsoncxx::type::k_int32);
ASSERT(doc[
"b"].
type() == bsoncxx::type::k_double);
ASSERT(doc[
"c"].
type() == bsoncxx::type::k_string);
ASSERT(doc["a"].get_value() == values[0]);
ASSERT(doc["b"].get_value() == values[1]);
ASSERT(doc["c"].get_value() == values[2]);
}
With a Sub-Document
void example() {
ASSERT(v[
"key"].get_string().
value.compare(
"value") == 0);
}
With Multiple Sub-Document Appends
void example() {
std::string keys[] = {"a", "b", "c"};
std::int32_t values[] = {1, 2, 3};
for (int i = 0; i < 3; ++i) {
doc.append(
kvp(keys[i], values[i]));
}
}));
ASSERT(v["a"].get_int32().value == 1);
ASSERT(v["b"].get_int32().value == 2);
ASSERT(v["c"].get_int32().value == 3);
}
With a Sub-Array
void example() {
ASSERT(v[0].
type() == bsoncxx::type::k_int32);
ASSERT(v[1].
type() == bsoncxx::type::k_int64);
ASSERT(v[0].get_int32().value == 1);
ASSERT(v[1].get_int64().value == 2);
}
With Multiple Sub-Array Appends
void example() {
std::int32_t values[] = {1, 2, 3};
for (int i = 0; i < 3; ++i) {
arr.append(values[i]);
}
}));
ASSERT(v[0].get_int32().value == 1);
ASSERT(v[1].get_int32().value == 2);
ASSERT(v[2].get_int32().value == 3);
}
From Raw Bytes
As a View
void example(const std::uint8_t* data, std::size_t length) {
ASSERT(doc[
"key"].get_string().
value.compare(
"value") == 0);
}
As a Value
void example(const std::uint8_t* data, std::size_t length) {
using deleter_type = bsoncxx::document::value::deleter_type;
std::uint8_t* raw = new std::uint8_t[length];
std::copy_n(data, length, raw);
deleter_type deleter = [](std::uint8_t* data) { delete[] data; };
ASSERT(doc[
"key"].get_string().
value.compare(
"value") == 0);
}
Create an Array
From a JSON String
Basic Example
void example() {
[1, 2.0, "three"]
)");
ASSERT(doc["0"].get_int32().value == 1);
ASSERT(doc["1"].get_double().value == 2.0);
ASSERT(doc[
"2"].get_string().
value.compare(
"three") == 0);
}
With Extended JSON
void example() {
[
{"$numberInt": "1"},
{"$numberLong": "2"},
{"$numberDouble": "3"}
]
)");
ASSERT(doc["0"].get_int32().value == 1);
ASSERT(doc["1"].get_int64().value == 2);
ASSERT(doc["2"].get_double().value == 3.0);
}
With a Sub-Document
void example() {
[
{"key": "value"}
]
)");
ASSERT(v[
"key"].get_string().
value.compare(
"value") == 0);
}
With a Sub-Array
void example() {
[
[1, 2]
]
)");
ASSERT(sub[0].get_int32().value == 1);
ASSERT(sub[1].get_int32().value == 2);
}
With a User-Defined Literal
void example() {
ASSERT(a == b);
}
Using the Basic Builder
Basic Example
void example() {
builder.append(std::int32_t{1}, 2.0, "three");
ASSERT(arr[0].get_int32().value == 1);
ASSERT(arr[1].get_double().value == 2.0);
ASSERT(arr[2].get_string().
value.compare(
"three") == 0);
}
With make_document
void example() {
ASSERT(arr[0].get_int32().value == 1);
ASSERT(arr[1].get_double().value == 2.0);
ASSERT(arr[2].get_string().
value.compare(
"three") == 0);
}
With Multiple Appends
void example() {
builder.append(std::int32_t{1});
builder.append(2.0);
builder.append("three");
ASSERT(arr[0].get_int32().value == 1);
ASSERT(arr[1].get_double().value == 2.0);
ASSERT(arr[2].get_string().
value.compare(
"three") == 0);
}
To Create Multiple Documents
void example() {
builder.append(std::int32_t{1});
builder.clear();
builder.append(std::int64_t{2});
ASSERT(a[0].
type() == bsoncxx::type::k_int32);
ASSERT(b[0].
type() == bsoncxx::type::k_int64);
ASSERT(a[0].get_int32().value == 1);
ASSERT(b[0].get_int64().value == 2);
}
With a Value Type
void example() {
ASSERT(arr[0].
type() == bsoncxx::type::k_int32);
ASSERT(arr[1].
type() == bsoncxx::type::k_double);
ASSERT(arr[2].
type() == bsoncxx::type::k_string);
ASSERT(arr[0].get_int32().value == 1);
ASSERT(arr[1].get_double().value == 2.0);
ASSERT(arr[2].get_string().
value.compare(
"three") == 0);
}
With a BSON Type
void example() {
ASSERT(arr[0].
type() == bsoncxx::type::k_int32);
ASSERT(arr[1].
type() == bsoncxx::type::k_double);
ASSERT(arr[2].
type() == bsoncxx::type::k_string);
ASSERT(arr[0].get_int32().value == 1);
ASSERT(arr[1].get_double().value == 2.0);
ASSERT(arr[2].get_string().
value.compare(
"three") == 0);
}
With a BSON Value
void example() {
std::int32_t{1},
2.0,
"three",
};
ASSERT(arr[0].
type() == bsoncxx::type::k_int32);
ASSERT(arr[1].
type() == bsoncxx::type::k_double);
ASSERT(arr[2].
type() == bsoncxx::type::k_string);
ASSERT(arr[0].get_value() == values[0]);
ASSERT(arr[1].get_value() == values[1]);
ASSERT(arr[2].get_value() == values[2]);
}
With a Sub-Document
void example() {
ASSERT(v[
"key"].get_string().
value.compare(
"value") == 0);
}
With Multiple Sub-Document Appends
void example() {
std::string keys[] = {"a", "b", "c"};
std::int32_t values[] = {1, 2, 3};
for (int i = 0; i < 3; ++i) {
doc.append(
kvp(keys[i], values[i]));
}
});
ASSERT(v["a"].get_int32().value == 1);
ASSERT(v["b"].get_int32().value == 2);
ASSERT(v["c"].get_int32().value == 3);
}
With a Sub-Array
void example() {
ASSERT(v[0].
type() == bsoncxx::type::k_int32);
ASSERT(v[1].
type() == bsoncxx::type::k_int64);
ASSERT(v[0].get_int32().value == 1);
ASSERT(v[1].get_int64().value == 2);
}
With Multiple Sub-Array Appends
void example() {
std::int32_t values[] = {1, 2, 3};
for (int i = 0; i < 3; ++i) {
arr.append(values[i]);
}
});
ASSERT(v[0].get_int32().value == 1);
ASSERT(v[1].get_int32().value == 2);
ASSERT(v[2].get_int32().value == 3);
}
From Raw Bytes
As a View
void example(const std::uint8_t* data, std::size_t length) {
ASSERT(arr[0].get_int32().value == 1);
ASSERT(arr[1].get_int32().value == 2);
}
As a Value
void example(const std::uint8_t* data, std::size_t length) {
using deleter_type = bsoncxx::array::value::deleter_type;
std::uint8_t* raw = new std::uint8_t[length];
std::copy_n(data, length, raw);
deleter_type deleter = [](std::uint8_t* data) { delete[] data; };
ASSERT(arr[0].get_int32().value == 1);
ASSERT(arr[1].get_int32().value == 2);
}
Access a Document Element
By Iteration
Basic Example
switch (e.type()) {
case bsoncxx::type::k_int32:
ASSERT(e.key().compare("a") == 0);
ASSERT(e.get_int32().value == 1);
break;
case bsoncxx::type::k_double:
ASSERT(e.key().compare("b") == 0);
ASSERT(e.get_double().value == 2.0);
break;
case bsoncxx::type::k_string:
ASSERT(e.key().compare("c") == 0);
ASSERT(e.get_string().value.compare("three") == 0);
break;
}
}
}
Using Iterators
ASSERT(doc.begin() != doc.end());
auto iter = doc.begin();
ASSERT(iter == doc.begin());
{
ASSERT(e.key().compare("a") == 0);
ASSERT(e.get_int32().value == 1);
}
++iter;
ASSERT(iter->key().compare("b") == 0);
ASSERT(iter->get_int32().value == 2);
{
auto iter_copy = iter++;
ASSERT(iter_copy != iter);
ASSERT(iter_copy->key().compare("b") == 0);
ASSERT(iter_copy->get_int32() == 2);
}
ASSERT(iter == doc.end());
}
Using Algorithms
ASSERT(std::distance(doc.begin(), doc.end()) == 3);
std::vector<bsoncxx::document::element> elements;
std::copy_if(doc.begin(),
doc.end(),
std::back_inserter(elements),
return e.key().compare("a") == 0 || e.type() == bsoncxx::type::k_string;
});
ASSERT(elements.size() == 2u);
ASSERT(elements[0].key().compare("a") == 0);
ASSERT(elements[1].key().compare("c") == 0);
}
By Key
Using find()
ASSERT(doc.find("a") == doc.begin());
{
auto iter = doc.find("b");
ASSERT(iter != doc.end());
ASSERT(iter->key().compare("b") == 0);
ASSERT(iter->get_int32().value == 2);
}
ASSERT(doc.find("x") == doc.end());
}
Using the Subscript Operator
ASSERT(doc["a"]);
{
ASSERT(e.key().compare("b") == 0);
ASSERT(e.get_int32().value == 2);
}
ASSERT(!doc["c"]);
}
Access an Array Element
By Iteration
Basic Example
switch (e.type()) {
case bsoncxx::type::k_int32:
ASSERT(e.key().compare("0") == 0);
ASSERT(e.get_int32().value == 1);
break;
case bsoncxx::type::k_double:
ASSERT(e.key().compare("1") == 0);
ASSERT(e.get_double().value == 2.0);
break;
case bsoncxx::type::k_string:
ASSERT(e.key().compare("2") == 0);
ASSERT(e.get_string().value.compare("three") == 0);
break;
}
}
}
Using Iterators
ASSERT(arr.begin() != arr.end());
auto iter = arr.begin();
ASSERT(iter == arr.begin());
{
ASSERT(e.key().compare("0") == 0);
ASSERT(e.get_int32().value == 1);
}
++iter;
ASSERT(iter->key().compare("1") == 0);
ASSERT(iter->get_int32().value == 2);
{
auto iter_copy = iter++;
ASSERT(iter_copy != iter);
ASSERT(iter_copy->key().compare("1") == 0);
ASSERT(iter_copy->get_int32() == 2);
}
ASSERT(iter == arr.end());
}
Using Algorithms
ASSERT(std::distance(arr.begin(), arr.end()) == 3);
std::vector<bsoncxx::array::element> elements;
std::copy_if(
return e.key().compare("0") == 0 || e.type() == bsoncxx::type::k_string;
});
ASSERT(elements.size() == 2u);
ASSERT(elements[0].key().compare("0") == 0);
ASSERT(elements[1].key().compare("2") == 0);
}
By Key
Using find()
ASSERT(arr.find(0) == arr.begin());
{
auto iter = arr.find(1);
ASSERT(iter != arr.end());
ASSERT(iter->key().compare("1") == 0);
ASSERT(iter->get_int32().value == 2);
}
ASSERT(arr.find(2) == arr.end());
}
Using the Subscript Operator
ASSERT(arr[0]);
{
ASSERT(e.key().compare("1") == 0);
ASSERT(e.get_int32().value == 2);
}
ASSERT(!arr[2]);
}
Query an Element
In a Document
For a Single Type
if (e.type() == bsoncxx::type::k_int32) {
ASSERT(e.key().compare("a") == 0);
ASSERT(v.type_id == bsoncxx::type::k_int32);
ASSERT(v.value == 1);
} else {
ASSERT(e.key().compare("a") != 0);
}
}
For Multiple Types
switch (e.type()) {
case bsoncxx::type::k_int32: {
ASSERT(e.key().compare("a") == 0);
ASSERT(v.type_id == bsoncxx::type::k_int32);
ASSERT(v.value == 1);
break;
}
case bsoncxx::type::k_double: {
ASSERT(e.key().compare("b") == 0);
ASSERT(v.type_id == bsoncxx::type::k_double);
ASSERT(v.value == 2.0);
break;
}
case bsoncxx::type::k_string: {
ASSERT(e.key().compare("c") == 0);
ASSERT(v.type_id == bsoncxx::type::k_string);
ASSERT(v.value.compare("three") == 0);
break;
}
}
}
In an Array
For Single Type
if (e.type() == bsoncxx::type::k_int32) {
ASSERT(e.key().compare("0") == 0);
ASSERT(v.type_id == bsoncxx::type::k_int32);
ASSERT(v.value == 1);
} else {
ASSERT(e.key().compare("0") != 0);
}
}
For Multiple Types
switch (e.type()) {
case bsoncxx::type::k_int32: {
ASSERT(e.key().compare("0") == 0);
ASSERT(v.type_id == bsoncxx::type::k_int32);
ASSERT(v.value == 1);
break;
}
case bsoncxx::type::k_double: {
ASSERT(e.key().compare("1") == 0);
ASSERT(v.type_id == bsoncxx::type::k_double);
ASSERT(v.value == 2.0);
break;
}
case bsoncxx::type::k_string: {
ASSERT(e.key().compare("2") == 0);
ASSERT(v.type_id == bsoncxx::type::k_string);
ASSERT(v.value.compare("three") == 0);
break;
}
}
}
Comparison
By Type
std::int32_t a{1};
std::int64_t b{2};
if (e.type() == bsoncxx::type::k_int32) {
ASSERT(e.key().compare("a") == 0);
ASSERT(e.get_int32().value == a);
} else if (e.type() == bsoncxx::type::k_int64) {
ASSERT(e.key().compare("b") == 0);
ASSERT(e.get_int64().value == b);
}
}
By BSON Value
if (e.get_value() == a) {
ASSERT(e.key().compare("a") == 0);
} else if (e.get_value() == b) {
ASSERT(e.key().compare("b") == 0);
}
if (e == va) {
ASSERT(e.key().compare("a") == 0);
} else if (e == vb) {
ASSERT(e.key().compare("b") == 0);
}
}
Obtain a BSON Value
From a BSON Type
As a View
void example() {
view_type v;
ASSERT(v.type() == bsoncxx::type::k_null);
v = view_type(v0);
ASSERT(v.type() == v0.type_id);
ASSERT(v.get_int32() == v0);
v = view_type(v1);
ASSERT(v.type() == v1.type_id);
ASSERT(v.get_double() == v1);
v = view_type(v2);
ASSERT(v.type() == v2.type_id);
ASSERT(v.get_string() == v2);
}
As a Value
void example() {
ASSERT(v.view().type() == bsoncxx::type::k_null);
ASSERT(v.view().type() == bsoncxx::type::k_int32);
ASSERT(v.view().get_int32().value == 1);
ASSERT(v.view().type() == bsoncxx::type::k_double);
ASSERT(v.view().get_double().value == 2.0);
ASSERT(v.view().type() == bsoncxx::type::k_string);
ASSERT(v.view().get_string().value.compare("three") == 0);
}
From a Document Element
As a View
ASSERT(v.type() == e.type());
switch (v.type()) {
case bsoncxx::type::k_int32:
ASSERT(e.key().compare("a") == 0);
ASSERT(v.get_int32() == e.get_int32());
break;
case bsoncxx::type::k_double:
ASSERT(e.key().compare("b") == 0);
ASSERT(v.get_double() == e.get_double());
break;
case bsoncxx::type::k_string:
ASSERT(e.key().compare("c") == 0);
ASSERT(v.get_string() == e.get_string());
break;
}
}
As a Value
void example() {
ASSERT(v.view().type() == bsoncxx::type::k_null);
["v"]
.get_owning_value();
ASSERT(v.view().type() == bsoncxx::type::k_document);
v = v.view().get_document().value["key"].get_string();
ASSERT(v.view().type() == bsoncxx::type::k_string);
ASSERT(v.view().get_string().value.compare("value") == 0);
}
From an Array Element
As a View
ASSERT(v.type() == e.type());
switch (v.type()) {
case bsoncxx::type::k_int32:
ASSERT(e.key().compare("0") == 0);
ASSERT(v.get_int32() == e.get_int32());
break;
case bsoncxx::type::k_double:
ASSERT(e.key().compare("1") == 0);
ASSERT(v.get_double() == e.get_double());
break;
case bsoncxx::type::k_string:
ASSERT(e.key().compare("2") == 0);
ASSERT(v.get_string() == e.get_string());
break;
}
}
As a Value
void example() {
ASSERT(v.view().type() == bsoncxx::type::k_null);
["v"]
.get_owning_value();
ASSERT(v.view().type() == bsoncxx::type::k_array);
v = v.view().get_array().value[0].get_string();
ASSERT(v.view().type() == bsoncxx::type::k_string);
ASSERT(v.view().get_string().value.compare("value") == 0);
}
From a Value Type
void example() {
ASSERT(v.view().type() == bsoncxx::type::k_null);
v = std::int32_t{1};
ASSERT(v.view().type() == bsoncxx::type::k_int32);
ASSERT(v.view().get_int32().value == 1);
v = 2.0;
ASSERT(v.view().type() == bsoncxx::type::k_double);
ASSERT(v.view().get_double().value == 2.0);
v = std::string("three");
ASSERT(v.view().type() == bsoncxx::type::k_string);
ASSERT(v.view().get_string().value.compare("three") == 0);
}
With make_value
void example() {
{
view_type v = owner.view();
ASSERT(v.type() == bsoncxx::type::k_int32);
ASSERT(v.get_int32().value == 1);
}
{
view_type v = owner.
view();
ASSERT(v.type() == bsoncxx::type::k_int64);
ASSERT(v.get_int64().value == 2);
}
{
view_type v = owner.view();
ASSERT(v.type() == bsoncxx::type::k_string);
ASSERT(v.get_string().value.compare("three") == 0);
}
}
Convert to a JSON String
From a Document
void example() {
std::uint8_t data[]{"three"};
auto data_len = static_cast<std::uint32_t>(sizeof(data) - 1u);
kvp(
"a", std::int32_t{1}),
kvp(
"b", std::int64_t{2}),
);
{
ASSERT(
json ==
R"({ "a" : { "$numberInt" : "1" }, "b" : { "$numberLong" : "2" }, "c" : { "$binary" : { "base64" : "dGhyZWU=", "subType" : "00" } } })");
}
{
ASSERT(
json ==
R"({ "a" : 1, "b" : 2, "c" : { "$binary" : { "base64" : "dGhyZWU=", "subType" : "00" } } })");
}
{
ASSERT(json == R"({ "a" : 1, "b" : 2, "c" : { "$binary" : "dGhyZWU=", "$type" : "00" } })");
}
{
ASSERT(a == b);
}
}
From an Array
void example() {
std::uint8_t data[]{"three"};
std::uint32_t data_len{5u};
std::int32_t{1},
std::int64_t{2},
binary
);
{
ASSERT(
json ==
R"([ { "$numberInt" : "1" }, { "$numberLong" : "2" }, { "$binary" : { "base64" : "dGhyZWU=", "subType" : "00" } } ])");
}
{
ASSERT(json == R"([ 1, 2, { "$binary" : { "base64" : "dGhyZWU=", "subType" : "00" } } ])");
}
{
ASSERT(json == R"([ 1, 2, { "$binary" : "dGhyZWU=", "$type" : "00" } ])");
}
{
ASSERT(a == b);
}
}