---
name: "bson_tutorial"
section: "3"
platform: "linux"
package: "libbson-doc"
version: "1.23.1-1+deb12u3"
release: "Debian 12 (Bookworm)"
platforms: ["linux"]
url: "https://new.carta.tech/bson_tutorial"
---

# bson\_tutorial(3)

Tutorial

## NAME

bson\_tutorial - Tutorial

## USING LIBBSON IN YOUR C PROGRAM

### Include bson.h

All libbson's functions and types are available in one header file. Simply include **bson.h**:

hello\_bson.c

```
#include <stdio.h>
#include <bson/bson.h>
int
main (int argc, const char **argv)
{
   bson_t *b;
   char *j;
   b = BCON_NEW ("hello", BCON_UTF8 ("bson!"));
   j = bson_as_canonical_extended_json (b, NULL);
   printf ("%s\n", j);
   bson_free (j);
   bson_destroy (b);
   return 0;
}
```

### CMake

The libbson installation includes a *CMake config-file package*, so you can use CMake's *find\_package* command to import libbson's CMake target and link to libbson (as a shared library):

CMakeLists.txt

```
# Specify the minimum version you require.
find_package (bson-1.0 1.7 REQUIRED)
# The "hello_bson.c" sample program is shared among four tests.
add_executable (hello_bson ../../hello_bson.c)
target_link_libraries (hello_bson PRIVATE mongo::bson_shared)
```

You can also use libbson as a static library instead: Use the **mongo::bson\_static** CMake target:

```
# Specify the minimum version you require.
find_package (bson-1.0 1.7 REQUIRED)
# The "hello_bson.c" sample program is shared among four tests.
add_executable (hello_bson ../../hello_bson.c)
target_link_libraries (hello_bson PRIVATE mongo::bson_static)
```

### pkg-config

If you're not using CMake, use *pkg-config* on the command line to set header and library paths:

```
gcc -o hello_bson hello_bson.c $(pkg-config --libs --cflags libbson-1.0)
```

Or to statically link to libbson:

```
gcc -o hello_bson hello_bson.c $(pkg-config --libs --cflags libbson-static-1.0)
```

## CREATING A BSON DOCUMENT

### The bson\_t structure

BSON documents are created using the *bson\_t* structure. This structure encapsulates the necessary logic for encoding using the *BSON Specification*. At the core, *bson\_t* is a buffer manager and set of encoding routines.

**TIP:**

BSON documents can live on the stack or the heap based on the performance needs or preference of the consumer.

Let's start by creating a new BSON document on the stack. Whenever using libbson, make sure you **#include \<bson/bson.h\>**.

```
bson_t b;
bson_init (&b);
```

This creates an empty document. In JSON, this would be the same as **{}**.

We can now proceed to adding items to the BSON document. A variety of functions prefixed with **bson\_append\_** can be used based on the type of field you want to append. Let's append a UTF-8 encoded string.

```
bson_append_utf8 (&b, "key", -1, "value", -1);
```

Notice the two **-1** parameters. The first indicates that the length of **key** in bytes should be determined with **strlen()**. Alternatively, we could have passed the number **3**. The same goes for the second **-1**, but for **value**.

Libbson provides macros to make this less tedious when using string literals. The following two appends are identical.

```
bson_append_utf8 (&b, "key", -1, "value", -1);
BSON_APPEND_UTF8 (&b, "key", "value");
```

Now let's take a look at an example that adds a few different field types to a BSON document.

```
bson_t b = BSON_INITIALIZER;
BSON_APPEND_INT32 (&b, "a", 1);
BSON_APPEND_UTF8 (&b, "hello", "world");
BSON_APPEND_BOOL (&b, "bool", true);
```

Notice that we omitted the call to *bson\_init()*. By specifying **BSON\_INITIALIZER** we can remove the need to initialize the structure to a base state.

### Sub-Documents and Sub-Arrays

To simplify the creation of sub-documents and arrays, *bson\_append\_document\_begin()* and *bson\_append\_array\_begin()* exist. These can be used to build a sub-document using the parent documents memory region as the destination buffer.

```
bson_t parent;
bson_t child;
char *str;
bson_init (&parent);
bson_append_document_begin (&parent, "foo", 3, &child);
bson_append_int32 (&child, "baz", 3, 1);
bson_append_document_end (&parent, &child);
str = bson_as_canonical_extended_json (&parent, NULL);
printf ("%s\n", str);
bson_free (str);
bson_destroy (&parent);
```

```
{ "foo" : { "baz" : 1 } }
```

### Simplified BSON C Object Notation

Creating BSON documents by hand can be tedious and time consuming. BCON, or BSON C Object Notation, was added to allow for the creation of BSON documents in a format that looks closer to the destination format.

The following example shows the use of BCON. Notice that values for fields are wrapped in the **BCON\_\*** macros. These are required for the variadic processor to determine the parameter type.

```
bson_t *doc;
doc = BCON_NEW ("foo",
                "{",
                "int",
                BCON_INT32 (1),
                "array",
                "[",
                BCON_INT32 (100),
                "{",
                "sub",
                BCON_UTF8 ("value"),
                "}",
                "]",
                "}");
```

Creates the following document

```
{ "foo" : { "int" : 1, "array" : [ 100, { "sub" : "value" } ] } }
```

## HANDLING ERRORS

### Description

Many libbson functions report errors by returning **NULL** or -1 and filling out a *bson\_error\_t* structure with an error domain, error code, and message.

- •

  **error.domain** names the subsystem that generated the error.

- •

  **error.code** is a domain-specific error type.

- •

  **error.message** describes the error.

Some error codes overlap with others; always check both the domain and code to determine the type of error.

| | | |
| --- | --- | --- |
| **BSON\_ERROR\_JSON** | **BSON\_JSON\_ERROR\_READ\_CORRUPT\_JS** **BSON\_JSON\_ERROR\_READ\_INVALID\_PARAM** **BSON\_JSON\_ERROR\_READ\_CB\_FAILURE** | *bson\_json\_reader\_t* tried to parse invalid MongoDB Extended JSON. Tried to parse a valid JSON document that is invalid as MongoDBExtended JSON. An internal callback failure during JSON parsing. |
| **BSON\_ERROR\_READER** | **BSON\_ERROR\_READER\_BADFD** | *bson\_json\_reader\_new\_from\_file()* could not open the file. |

## OBJECTIDS

Libbson provides a simple way to generate ObjectIDs. It can be used in a single-threaded or multi-threaded manner depending on your requirements.

The *bson\_oid\_t* structure represents an **ObjectID** in MongoDB. It is a 96-bit identifier.

### Composition

- •

  4 bytes : The UNIX timestamp in big-endian format.

- •

  5 bytes : A random number.

- •

  3 bytes : A 24-bit monotonic counter incrementing from **rand()** in big-endian.

### Sorting ObjectIDs

The typical way to sort in C is using **qsort()**. Therefore, Libbson provides a **qsort()** compatible callback function named *bson\_oid\_compare()*. It returns **less than 1**, **greater than 1**, or **0** depending on the equality of two *bson\_oid\_t* structures.

### Comparing Object IDs

If you simply want to compare two *bson\_oid\_t* structures for equality, use *bson\_oid\_equal()*.

### Generating

To generate a *bson\_oid\_t*, you may use the following.

```
bson_oid_t oid;
bson_oid_init (&oid, NULL);
```

### Parsing ObjectID Strings

You can also parse a string containing a *bson\_oid\_t*. The input string *MUST* be 24 characters or more in length.

```
bson_oid_t oid;
bson_oid_init_from_string (&oid, "123456789012345678901234");
```

```
bson_oid_t oid;
bson_oid_init_from_string_unsafe (&oid, "123456789012345678901234");
```

### Hashing ObjectIDs

If you need to store items in a hashtable, you may want to use the *bson\_oid\_t* as the key. Libbson provides a hash function for just this purpose. It is based on DJB hash.

```
unsigned hash;
hash = bson_oid_hash (oid);
```

### Fetching ObjectID Creation Time

You can easily fetch the time that a *bson\_oid\_t* was generated using *bson\_oid\_get\_time\_t()*.

```
time_t t;
t = bson_oid_get_time_t (oid);
printf ("The OID was generated at %u\n", (unsigned) t);
```

## PARSING AND ITERATING BSON DOCUMENTS

### Parsing

BSON documents are lazily parsed as necessary. To begin parsing a BSON document, use one of the provided Libbson functions to create a new *bson\_t* from existing data such as *bson\_new\_from\_data()*. This will make a copy of the data so that additional mutations may occur to the BSON document.

**TIP:**

If you only want to parse a BSON document and have no need to mutate it, you may use *bson\_init\_static()* to avoid making a copy of the data.

```
bson_t *b;
b = bson_new_from_data (my_data, my_data_len);
if (!b) {
   fprintf (stderr, "The specified length embedded in <my_data> did not match "
                    "<my_data_len>\n");
   return;
}
bson_destroy (b);
```

Only two checks are performed when creating a new *bson\_t* from an existing buffer. First, the document must begin with the buffer length, matching what was expected by the caller. Second, the document must end with the expected trailing **\\0** byte.

To parse the document further we use a *bson\_iter\_t* to iterate the elements within the document. Let's print all of the field names in the document.

```
bson_t *b;
bson_iter_t iter;
if ((b = bson_new_from_data (my_data, my_data_len))) {
   if (bson_iter_init (&iter, b)) {
      while (bson_iter_next (&iter)) {
         printf ("Found element key: \"%s\"\n", bson_iter_key (&iter));
      }
   }
   bson_destroy (b);
}
```

Converting a document to JSON uses a *bson\_iter\_t* and *bson\_visitor\_t* to iterate all fields of a BSON document recursively and generate a UTF-8 encoded JSON string.

```
bson_t *b;
char *json;
if ((b = bson_new_from_data (my_data, my_data_len))) {
   if ((json = bson_as_canonical_extended_json (b, NULL))) {
      printf ("%s\n", json);
      bson_free (json);
   }
   bson_destroy (b);
}
```

### Recursing into Sub-Documents

Libbson provides convenient sub-iterators to dive down into a sub-document or sub-array. Below is an example that will dive into a sub-document named "foo" and print it's field names.

```
bson_iter_t iter;
bson_iter_t child;
char *json;
if (bson_iter_init_find (&iter, doc, "foo") &&
    BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) {
   while (bson_iter_next (&child)) {
      printf ("Found sub-key of \"foo\" named \"%s\"\n",
              bson_iter_key (&child));
   }
}
```

### Finding Fields using Dot Notation

Using the *bson\_iter\_recurse()* function exemplified above, *bson\_iter\_find\_descendant()* can find a field for you using the MongoDB style path notation such as "foo.bar.0.baz".

Let's create a document like **{"foo": {"bar": \[{"baz: 1}\]}}** and locate the **"baz"** field.

```
bson_t *b;
bson_iter_t iter;
bson_iter_t baz;
b =
   BCON_NEW ("foo", "{", "bar", "[", "{", "baz", BCON_INT32 (1), "}", "]", "}");
if (bson_iter_init (&iter, b) &&
    bson_iter_find_descendant (&iter, "foo.bar.0.baz", &baz) &&
    BSON_ITER_HOLDS_INT32 (&baz)) {
   printf ("baz = %d\n", bson_iter_int32 (&baz));
}
bson_destroy (b);
```

### Validating a BSON Document

If all you want to do is validate that a BSON document is valid, you can use *bson\_validate()*.

```
size_t err_offset;
if (!bson_validate (doc, BSON_VALIDATE_NONE, &err_offset)) {
   fprintf (stderr,
            "The document failed to validate at offset: %u\n",
            (unsigned) err_offset);
}
```

See the *bson\_validate()* documentation for more information and examples.

## UTF-8

### Encoding

Libbson expects that you are always working with UTF-8 encoded text. Anything else is **invalid API use**.

If you should need to walk through UTF-8 sequences, you can use the various UTF-8 helper functions distributed with Libbson.

### Validating a UTF-8 Sequence

To validate the string contained in **my\_string**, use the following. You may pass **-1** for the string length if you know the string is NULL-terminated.

```
if (!bson_utf8_validate (my_string, -1, false)) {
   printf ("Validation failed.\n");
}
```

If **my\_string** has NULL bytes within the string, you must provide the string length. Use the following format. Notice the **true** at the end indicating **\\0** is allowed.

```
if (!bson_utf8_validate (my_string, my_string_len, true)) {
   printf ("Validation failed.\n");
}
```

For more information see the API reference for *bson\_utf8\_validate()*.

## AUTHOR

MongoDB, Inc

## COPYRIGHT

2017-present, MongoDB, Inc
