1BSON_TUTORIAL(3) libbson BSON_TUTORIAL(3)
2
3
4
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
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
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
194 • error.domain names the subsystem that generated the error.
195
196 • error.code is a domain-specific error type.
197
198 • error.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 ┌──────────────────┬─────────────────────┬──────────────────────────────────┐
204 │BSON_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 ├──────────────────┼─────────────────────┼──────────────────────────────────┤
216 │BSON_ERROR_READER │ BSON_ER‐ │ bson_json_reader_new_from_file() │
217 │ │ ROR_READER_BADFD │ could not open the │
218 │ │ │ file. │
219 └──────────────────┴─────────────────────┴──────────────────────────────────┘
220
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
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
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
427 MongoDB, Inc
428
430 2017-present, MongoDB, Inc
431
432
433
434
4351.25.1 Nov 08, 2023 BSON_TUTORIAL(3)