Reading BSON Data#
Accessing BSON data is done with two types: bson_view and bson_iterator.
Getting a View#
For any function that expects a bson_view, a view can be created from a
bson_doc or bson_mut using bson_view_from():
void do_something(bson_view) { /* ... */ }
void get_view() {
bson_doc d = bson_new();
bson_mut m = bson_mutate(&d);
bson_insert(&m, "foo", "bar");
// Pass a view to `do_something`
do_something(bson_view_from(d));
bson_delete(d);
}
Obtaining an Iterator#
A bson_iterator referring to the first document element can be obtained using
bson_begin(). bson_begin() can be passed a bson_doc, a bson_view, or a
bson_mut:
void inspect_data(bson_view v) {
bson_iterator it = bson_begin(v);
printf("Element key is '%s'\n", bson_key(it).data);
}
An iterator created with bson_begin() will immediately refer to the first
element, or may refer to the past-the-end position if the document is empty.
An iterator referring to the past-the-end position is obtained using bson_end().
The bson_end() iterator does not view any element, but instead refers to the
final position in the element sequence.
Iterating over a Document#
Given a valid iterator, an iterator to the next element can be obtained by
calling bson_next() with that iterator. This can be done in a loop to iterate
over the elements of a document, using bson_stop() to check for an end or error
condition:
void do_loop(bson_view data) {
for (bson_iterator it = bson_begin(data); // init
!bson_stop(it); // guard
it = bson_next(it)) { // step
printf("Got an element: %s\n", bson_key(it).data);
}
}
Easy Mode#
In C, the macro bson_foreach can be used to iterate over document elements:
void foreach_loop(bson_view data) {
bson_foreach (it, data) {
// `it` refers to the current element.
printf("Got an element: %s\n", bson_key(it).data);
}
}
In C++, bson_doc, bson_mut, bson_view, bson::document, and
bson::mutator are all forward ranges and can be used with a regular C++ for
loop:
void cxx_for(bson_view data) {
for (bson_iterator::reference elem : data) {
// `it` refers to the current element.
printf("Got an element: %s\n", elem.key().data());
}
}
bson_iterator implements std::forward_iterator, and can be used with
standard algorithms.
Decoding Data#
Given an iterator referring to a valid element, we can decode it using the
bson_iterator_value() function:
void get_double(bson_view v) {
bson_iterator it = bson_begin(v);
assert(!bson_stop(it));
bson_value_ref val = bson_iterator_value(it);
if (val.type != bson_type_utf8) {
fputs("Expected a UTF-8 element", stderr);
return;
}
printf("Element '%s' has value '%*s'\n", bson_key(it).data, (int)val.utf8.len, val.utf8.data);
}
Example: Seek a Subdocument Element and Iterate It#
This example uses bson_find() to seek out a specific element in a document,
checks if its is an array, and then iterates over its elements:
void do_something_with(bson_iterator) { /* ... */ }
bool subdoc_iter(bson_view top) {
// Find an element called "some-array"
bson_iterator it = bson_find(top, "some-array");
if (bson_stop(it)) {
// The element was not found
fputs("Did not find a 'some-array' element", stderr);
return false;
}
bson_value_ref val = bson_iterator_value(it);
// Check that it is actually an array
if (val.type != bson_type_array) {
fputs("Expected an array element", stderr);
return false;
}
// Iterate over each element of the array
bson_foreach (sub_iter, val.array) {
if (bson_iterator_get_error(sub_iter)) {
// Iterating over a child element encountered an error
fprintf(stderr,
"A subdocument array element is malformed [error %d]",
bson_iterator_get_error(sub_iter));
return false;
}
// Pass an iterator within the child document:
do_something_with(sub_iter);
}
return true;
}