1BSON_TUTORIAL(3)                    libbson                   BSON_TUTORIAL(3)
2
3
4

USING LIBBSON IN YOUR C PROGRAM

6   Include bson.h
7       All  libbson's  functions  and  types are available in one header file.
8       Simply include bson.h:
9
10       hello_bson.c
11
12          #include <stdio.h>
13          #include <bson/bson.h>
14
15          int
16          main (int argc, const char **argv)
17          {
18             bson_t *b;
19             char *j;
20
21             b = BCON_NEW ("hello", BCON_UTF8 ("bson!"));
22             j = bson_as_canonical_extended_json (b, NULL);
23             printf ("%s\n", j);
24
25             bson_free (j);
26             bson_destroy (b);
27
28             return 0;
29          }
30
31
32   CMake
33       The libbson installation includes a CMake config-file package,  so  you
34       can  use  CMake's find_package command to import libbson's CMake target
35       and link to libbson (as a shared library):
36
37       CMakeLists.txt
38
39          # Specify the minimum version you require.
40          find_package (bson-1.0 1.7 REQUIRED)
41
42          # The "hello_bson.c" sample program is shared among four tests.
43          add_executable (hello_bson ../../hello_bson.c)
44          target_link_libraries (hello_bson PRIVATE mongo::bson_shared)
45
46
47       You can  also  use  libbson  as  a  static  library  instead:  Use  the
48       mongo::bson_static CMake target:
49
50          # Specify the minimum version you require.
51          find_package (bson-1.0 1.7 REQUIRED)
52
53          # The "hello_bson.c" sample program is shared among four tests.
54          add_executable (hello_bson ../../hello_bson.c)
55          target_link_libraries (hello_bson PRIVATE mongo::bson_static)
56
57
58   pkg-config
59       If  you're  not  using CMake, use pkg-config on the command line to set
60       header and library paths:
61
62          gcc -o hello_bson hello_bson.c $(pkg-config --libs --cflags libbson-1.0)
63
64
65       Or to statically link to libbson:
66
67          gcc -o hello_bson hello_bson.c $(pkg-config --libs --cflags libbson-static-1.0)
68
69

CREATING A BSON DOCUMENT

71   The bson_t structure
72       BSON documents are created using the bson_t structure.  This  structure
73       encapsulates the necessary logic for encoding using the BSON Specifica‐
74       tion. At the core, bson_t is a buffer manager and set of encoding  rou‐
75       tines.
76
77       TIP:
78          BSON  documents  can live on the stack or the heap based on the per‐
79          formance needs or preference of the consumer.
80
81       Let's start by creating a new BSON document on the stack. Whenever  us‐
82       ing libbson, make sure you #include <bson/bson.h>.
83
84          bson_t b;
85
86          bson_init (&b);
87
88       This creates an empty document. In JSON, this would be the same as {}.
89
90       We  can  now proceed to adding items to the BSON document. A variety of
91       functions prefixed with bson_append_ can be used based on the  type  of
92       field you want to append. Let's append a UTF-8 encoded string.
93
94          bson_append_utf8 (&b, "key", -1, "value", -1);
95
96       Notice  the  two  -1 parameters. The first indicates that the length of
97       key in bytes should be  determined  with  strlen().  Alternatively,  we
98       could  have  passed  the number 3. The same goes for the second -1, but
99       for value.
100
101       Libbson provides macros to make this less  tedious  when  using  string
102       literals. The following two appends are identical.
103
104          bson_append_utf8 (&b, "key", -1, "value", -1);
105          BSON_APPEND_UTF8 (&b, "key", "value");
106
107       Now  let's  take  a  look at an example that adds a few different field
108       types to a BSON document.
109
110          bson_t b = BSON_INITIALIZER;
111
112          BSON_APPEND_INT32 (&b, "a", 1);
113          BSON_APPEND_UTF8 (&b, "hello", "world");
114          BSON_APPEND_BOOL (&b, "bool", true);
115
116       Notice that we omitted the call to bson_init(). By specifying BSON_INI‐
117       TIALIZER  we  can remove the need to initialize the structure to a base
118       state.
119
120   Sub-Documents and Sub-Arrays
121       To simplify the creation of sub-documents  bson_append_document_begin()
122       can be used to build a sub-document using the parent's memory region as
123       the destination buffer.
124
125          bson_t parent = BSON_INITIALIZER;
126          bson_t child;
127
128          bson_append_document_begin (&parent, "foo", 3, &child);
129          bson_append_int32 (&child, "baz", 3, 1);
130          bson_append_document_end (&parent, &child);
131
132          char *str = bson_as_relaxed_extended_json (&parent, NULL);
133          printf ("%s\n", str); // Prints: { "foo" : { "baz" : 1 } }
134          bson_free (str);
135
136          bson_destroy (&parent);
137
138
139       To simplify the creation of sub-arrays bson_array_builder_t can be used
140       to  build  a sub-array using the parent's memory region as the destina‐
141       tion buffer.
142
143          bson_t parent = BSON_INITIALIZER;
144          bson_array_builder_t *bab;
145
146          bson_append_array_builder_begin (&parent, "foo", 3, &bab);
147          bson_array_builder_append_int32 (bab, 9);
148          bson_array_builder_append_int32 (bab, 8);
149          bson_array_builder_append_int32 (bab, 7);
150          bson_append_array_builder_end (&parent, bab);
151
152          char *str = bson_as_relaxed_extended_json (&parent, NULL);
153          printf ("%s\n", str); // Prints: { "foo" : [ 9, 8, 7 ] }
154          bson_free (str);
155
156          bson_destroy (&parent);
157
158
159   Simplified BSON C Object Notation
160       Creating BSON documents by hand can  be  tedious  and  time  consuming.
161       BCON, or BSON C Object Notation, was added to allow for the creation of
162       BSON documents in a format that looks closer to the destination format.
163
164       The following example shows the use of BCON.  Notice  that  values  for
165       fields  are  wrapped  in  the BCON_* macros. These are required for the
166       variadic processor to determine the parameter type.
167
168          bson_t *doc;
169
170          doc = BCON_NEW ("foo",
171                          "{",
172                          "int",
173                          BCON_INT32 (1),
174                          "array",
175                          "[",
176                          BCON_INT32 (100),
177                          "{",
178                          "sub",
179                          BCON_UTF8 ("value"),
180                          "}",
181                          "]",
182                          "}");
183
184       Creates the following document
185
186          { "foo" : { "int" : 1, "array" : [ 100, { "sub" : "value" } ] } }
187

HANDLING ERRORS

189   Description
190       Many libbson functions report errors by returning NULL or -1 and  fill‐
191       ing  out a bson_error_t structure with an error domain, error code, and
192       message.
193
194error.domain names the subsystem that generated the error.
195
196error.code is a domain-specific error type.
197
198error.message describes the error.
199
200       Some error codes overlap with others; always check both the domain  and
201       code to determine the type of error.
202
203     ┌──────────────────┬─────────────────────┬──────────────────────────────────┐
204BSON_ERROR_JSON   BSON_JSON_ER‐       bson_json_reader_t
205     │                  │ ROR_READ_CORRUPT_JS │ tried to parse  in‐              │
206     │                  │ BSON_JSON_ER‐       │ valid  MongoDB  Ex‐              │
207     │                  │ ROR_READ_IN‐        │ tended JSON.  Tried              │
208     │                  │ VALID_PARAM         │ to  parse  a  valid              │
209     │                  │ BSON_JSON_ER‐       │ JSON document  that              │
210     │                  │ ROR_READ_CB_FAILURE │ is  invalid as Mon‐              │
211     │                  │                     │ goDBExtended  JSON.              │
212     │                  │                     │ An  internal  call‐              │
213     │                  │                     │ back failure during              │
214     │                  │                     │ JSON parsing.                    │
215     ├──────────────────┼─────────────────────┼──────────────────────────────────┤
216BSON_ERROR_READER BSON_ER‐            bson_json_reader_new_from_file()
217     │                  │ ROR_READER_BADFD    │ could  not open the              │
218     │                  │                     │ file.                            │
219     └──────────────────┴─────────────────────┴──────────────────────────────────┘
220

OBJECTIDS

222       Libbson provides a simple way to generate ObjectIDs. It can be used  in
223       a  single-threaded  or multi-threaded manner depending on your require‐
224       ments.
225
226       The bson_oid_t structure represents an ObjectID in  MongoDB.  It  is  a
227       96-bit identifier.
228
229   Composition
230       • 4 bytes : The UNIX timestamp in big-endian format.
231
232       • 5 bytes : A random number.
233
234       • 3  bytes  :  A  24-bit  monotonic counter incrementing from rand() in
235         big-endian.
236
237   Sorting ObjectIDs
238       The typical way to sort in C is using qsort(). Therefore, Libbson  pro‐
239       vides  a qsort() compatible callback function named bson_oid_compare().
240       It returns less than 1, greater than 1, or 0 depending on the  equality
241       of two bson_oid_t structures.
242
243   Comparing Object IDs
244       If  you  simply want to compare two bson_oid_t structures for equality,
245       use bson_oid_equal().
246
247   Generating
248       To generate a bson_oid_t, you may use the following.
249
250          bson_oid_t oid;
251
252          bson_oid_init (&oid, NULL);
253
254   Parsing ObjectID Strings
255       You can also parse a string containing a bson_oid_t. The  input  string
256       MUST be 24 characters or more in length.
257
258          bson_oid_t oid;
259
260          bson_oid_init_from_string (&oid, "123456789012345678901234");
261
262          bson_oid_t oid;
263
264          bson_oid_init_from_string_unsafe (&oid, "123456789012345678901234");
265
266   Hashing ObjectIDs
267       If  you  need  to  store  items in a hashtable, you may want to use the
268       bson_oid_t as the key. Libbson provides a hash function for  just  this
269       purpose. It is based on DJB hash.
270
271          unsigned hash;
272
273          hash = bson_oid_hash (oid);
274
275   Fetching ObjectID Creation Time
276       You  can  easily  fetch  the time that a bson_oid_t was generated using
277       bson_oid_get_time_t().
278
279          time_t t;
280
281          t = bson_oid_get_time_t (oid);
282          printf ("The OID was generated at %u\n", (unsigned) t);
283

PARSING AND ITERATING BSON DOCUMENTS

285   Parsing
286       BSON documents are lazily parsed as necessary. To begin parsing a  BSON
287       document,  use  one  of  the provided Libbson functions to create a new
288       bson_t from existing data such as bson_new_from_data(). This will  make
289       a  copy  of the data so that additional mutations may occur to the BSON
290       document.
291
292       TIP:
293          If you only want to parse a BSON document and have no need to mutate
294          it,  you  may  use  bson_init_static() to avoid making a copy of the
295          data.
296
297          bson_t *b;
298
299          b = bson_new_from_data (my_data, my_data_len);
300          if (!b) {
301             fprintf (stderr, "The specified length embedded in <my_data> did not match "
302                              "<my_data_len>\n");
303             return;
304          }
305
306          bson_destroy (b);
307
308       Only two checks are performed when creating a new bson_t from an exist‐
309       ing  buffer.  First,  the  document  must begin with the buffer length,
310       matching what was expected by the caller. Second, the document must end
311       with the expected trailing \0 byte.
312
313       To  parse the document further we use a bson_iter_t to iterate the ele‐
314       ments within the document. Let's print all of the field  names  in  the
315       document.
316
317          bson_t *b;
318          bson_iter_t iter;
319
320          if ((b = bson_new_from_data (my_data, my_data_len))) {
321             if (bson_iter_init (&iter, b)) {
322                while (bson_iter_next (&iter)) {
323                   printf ("Found element key: \"%s\"\n", bson_iter_key (&iter));
324                }
325             }
326             bson_destroy (b);
327          }
328
329       Converting  a document to JSON uses a bson_iter_t and bson_visitor_t to
330       iterate all fields of a BSON document recursively and generate a  UTF-8
331       encoded JSON string.
332
333          bson_t *b;
334          char *json;
335
336          if ((b = bson_new_from_data (my_data, my_data_len))) {
337             if ((json = bson_as_canonical_extended_json (b, NULL))) {
338                printf ("%s\n", json);
339                bson_free (json);
340             }
341             bson_destroy (b);
342          }
343
344   Recursing into Sub-Documents
345       Libbson provides convenient sub-iterators to dive down into a sub-docu‐
346       ment or sub-array. Below is an example that will dive into a  sub-docu‐
347       ment named "foo" and print it's field names.
348
349          bson_iter_t iter;
350          bson_iter_t child;
351          char *json;
352
353          if (bson_iter_init_find (&iter, doc, "foo") &&
354              BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) {
355             while (bson_iter_next (&child)) {
356                printf ("Found sub-key of \"foo\" named \"%s\"\n",
357                        bson_iter_key (&child));
358             }
359          }
360
361   Finding Fields using Dot Notation
362       Using    the    bson_iter_recurse()    function    exemplified   above,
363       bson_iter_find_descendant() can find a field for you using the  MongoDB
364       style path notation such as "foo.bar.0.baz".
365
366       Let's  create  a document like {"foo": {"bar": [{"baz: 1}]}} and locate
367       the "baz" field.
368
369          bson_t *b;
370          bson_iter_t iter;
371          bson_iter_t baz;
372
373          b =
374             BCON_NEW ("foo", "{", "bar", "[", "{", "baz", BCON_INT32 (1), "}", "]", "}");
375
376          if (bson_iter_init (&iter, b) &&
377              bson_iter_find_descendant (&iter, "foo.bar.0.baz", &baz) &&
378              BSON_ITER_HOLDS_INT32 (&baz)) {
379             printf ("baz = %d\n", bson_iter_int32 (&baz));
380          }
381
382          bson_destroy (b);
383
384   Validating a BSON Document
385       If all you want to do is validate that a BSON document  is  valid,  you
386       can use bson_validate().
387
388          size_t err_offset;
389
390          if (!bson_validate (doc, BSON_VALIDATE_NONE, &err_offset)) {
391             fprintf (stderr,
392                      "The document failed to validate at offset: %u\n",
393                      (unsigned) err_offset);
394          }
395
396       See  the  bson_validate()  documentation for more information and exam‐
397       ples.
398

UTF-8

400   Encoding
401       Libbson expects that you are always working with  UTF-8  encoded  text.
402       Anything else is invalid API use.
403
404       If  you  should  need  to walk through UTF-8 sequences, you can use the
405       various UTF-8 helper functions distributed with Libbson.
406
407   Validating a UTF-8 Sequence
408       To validate the string contained in my_string, use the  following.  You
409       may pass -1 for the string length if you know the string is NULL-termi‐
410       nated.
411
412          if (!bson_utf8_validate (my_string, -1, false)) {
413             printf ("Validation failed.\n");
414          }
415
416       If my_string has NULL bytes within the string,  you  must  provide  the
417       string length. Use the following format. Notice the true at the end in‐
418       dicating \0 is allowed.
419
420          if (!bson_utf8_validate (my_string, my_string_len, true)) {
421             printf ("Validation failed.\n");
422          }
423
424       For more information see the API reference for bson_utf8_validate().
425

AUTHOR

427       MongoDB, Inc
428
430       2017-present, MongoDB, Inc
431
432
433
434
4351.25.1                           Nov 08, 2023                 BSON_TUTORIAL(3)
Impressum