The mongocxx driver ships with a new library, bsoncxx. This article will
go over some of the different types in this library, and how and when to
use each. For more information and example code, see our
examples.

Document Builders {#builders}

The various methods of creating BSON documents and arrays are all
equivalent. All interfaces will provide the same results, the choice of
which to use is entirely aesthetic.

"One-off" builder functions {#one-off}

The simplest way to create a BSON document or array is to use the one-off
builder functions, which create documents and arrays in a single call.
These can be used when no additional logic (such as conditionals or loops)
needs to be used to create the object:

NOTE: In order to properly append each new value, a stream builder
needs to keep track of the state of the current document, including the
nesting level and the type of the most recent value appended to the
builder. The initial stream builder must not be reused after this state
changes, which means that intermediate values must be stored in new
variables if a document is being built with the stream builder across
multiple statements. Because doing this properly is difficult and the
compiler error messages can be confusing, using the stream builder is
discouraged. We recommend instead using the basic builder or the
one-off builder functions.

Building arrays in loops

Sometimes it's necessary to build an array using a loop. With the basic
builder, a top-level array can be built by simply calling append inside
a loop:

When building an array with the stream builder, it's important to be aware
that the return type of using the << operator on a stream builder is not
uniform. To build an array in a loop properly, intermediate values
returned by the stream builder should be stored in variables when the type
changes. One attempt to build an array from a stream builder using a loop
might look like the following:

Note that the result of any stream operation should be captured, so if you want
to split the single statement within the for loop above into multiple
statements, you must capture each intermediate result. Additionally, the last
statement within the loop body should assign its result back to the in_array
object, so that the loop restarts in a consistent state:

Such methods can take either a document::view or a document::value. If
a document::value is passed in, it must be passed by r-value reference, so
ownership of the document is transferred to the method.

document::value ismaster = document{} << "ismaster" << 1 << finalize;
// You can pass a document::view into run_command()
db.run_command(ismaster.view());
// Or you can move in a document::value
db.run_command(std::move(ismaster));

You shouldn't need to create view_or_value types directly in order to use
the driver. They are offered as a convenience method to allow driver
methods to take documents in either an owning or non-owning way. The
view_or_value type also helps mitigate some of the lifetime issues
discussed in the next section.

It is imperative that document::values outlive any document::views that
use them. If the underlying value gets cleaned up, the view will be left
with a dangling pointer. Consider a method that returns a view of a
newly-created document:

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 returns a bsoncxx::document::element, which holds the actual desired value:

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 Types

The BSON specification provides a list
of supported types. These are represented in C++ using the
b_xxx
type wrappers.

Some BSON types don't necessarily have a native representation to wrap and
are implemented via special classes.

Decimal128

The bsoncxx::decimal128 class represents a 128-bit IEEE 754-2008 decimal
floating point value. We expect users to convert these to and from
strings, but provide access to the low and high 64-bit values if users need
to convert to a native decimal128 type.