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