Skip to content

Handling BSON in the new driver

Samantha Ritter edited this page Dec 7, 2015 · 14 revisions

The C++11 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 about the bsoncxx library and example code, see /examples/bsoncxx.

Document Builders

bsoncxx::builder::basic::document
bsoncxx::builder::stream::document

The bsoncxx library offers two different interfaces for building BSON, a basic builder and a stream-based builder. Both equivalent builder document types are helper objects for building up BSON from scratch. Either interface will provide the same results, the choice of which to use is entirely aesthetic.

Basic builder

using bsoncxx::builder::basic::kvp;

// { "hello" : "world" }
bsoncxx::builder::basic::document basic_builder{};
basic_builder.append(kvp("hello", "world"));

More advanced uses of the basic builder are shown in this example.

Stream builder

// { "hello" : "world" }
// Option 1 - build over multiple lines
bsoncxx::builder::stream::document stream_builder{};
stream_builder << "hello" << "world";

// Option 2 - build in a single line
auto stream_builder = bsoncxx::builder::stream::document{} << "hello" << "world";

More advanced uses of the stream builder are shown in this example.

The code above, for either interface, produces builder documents, which are not yet BSON documents. The builder documents will need to be converted to fully-fledged BSON documents to be used.

Owning BSON Documents (values)

bsoncxx::document::value

This type represents an actual BSON document, one that owns its buffer of data. These documents can be constructed from a builder by calling extract():

bsoncxx::document::value basic_doc{basic_builder.extract()};
bsoncxx::document::value stream_doc{stream_builder.extract()};

Note that after calling extract() the builder is in a moved-from state, and should not be used.

It's possible to create a bsoncxx::document::value in a single line using the stream builder interface and the finalize token. finalize returns a document::value from a temporary stream builder:

// { "finalize" : "is nifty" }
bsoncxx::document::value one_line = bsoncxx::builder::stream::document{} << "finalize" << "is nifty" << bsoncxx::builder::stream::finalize;

Non-owning BSON Documents (views)

bsoncxx::document::view

This type is a view into an owning bsoncxx::document::value.

bsoncxx::document::view document_view{document_value.view()};

A document::value also implicitly converts to a document::view:

bsoncxx::document::view document_view{document_value};

In performance-critical code, passing views around is preferable to using values because we can avoid excess copying. Also, passing a view of a document allows us to use the document multiple times:

// { "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 Document Lifetime

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 method returns a dangling view that should not be used:

// This view contains a dangling pointer
bsoncxx::document::view dangling_view = make_a_dangling_view(); // Warning!!

Attempting to create a view off of a builder will similarly create a dangerous view object, because the temporary value returned from extract() isn't captured:

bsoncxx::builder::stream::document temp_builder{};
temp_builder << "oh" << "no";
bsoncxx::document::view dangling_view = temp_builder.extract().view(); // Bad!!

Printing BSON documents

bsoncxx::to_json()

The bsoncxx library comes with a convenience method to convert BSON documents to strings for easy inspection:

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

There is an analogous method, from_json(), to build document::values out of existing JSON strings.

Clone this wiki locally