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