1BSON_TUTORIAL(3) libbson BSON_TUTORIAL(3)
2
3
4
6 bson_tutorial - Tutorial
7
9 Include bson.h
10 All libbson's functions and types are available in one header file.
11 Simply include bson.h:
12
13 hello_bson.c
14
15 #include <stdio.h>
16 #include <bson/bson.h>
17
18 int
19 main (int argc, const char **argv)
20 {
21 bson_t *b;
22 char *j;
23
24 b = BCON_NEW ("hello", BCON_UTF8 ("bson!"));
25 j = bson_as_canonical_extended_json (b, NULL);
26 printf ("%s\n", j);
27
28 bson_free (j);
29 bson_destroy (b);
30
31 return 0;
32 }
33
34
35 CMake
36 The libbson installation includes a CMake config-file package, so you
37 can use CMake's find_package command to import libbson's CMake target
38 and link to libbson (as a shared library):
39
40 CMakeLists.txt
41
42 # Specify the minimum version you require.
43 find_package (bson-1.0 1.7 REQUIRED)
44
45 # The "hello_bson.c" sample program is shared among four tests.
46 add_executable (hello_bson ../../hello_bson.c)
47 target_link_libraries (hello_bson PRIVATE mongo::bson_shared)
48
49
50 You can also use libbson as a static library instead: Use the
51 mongo::bson_static CMake target:
52
53 # Specify the minimum version you require.
54 find_package (bson-1.0 1.7 REQUIRED)
55
56 # The "hello_bson.c" sample program is shared among four tests.
57 add_executable (hello_bson ../../hello_bson.c)
58 target_link_libraries (hello_bson PRIVATE mongo::bson_static)
59
60
61 pkg-config
62 If you're not using CMake, use pkg-config on the command line to set
63 header and library paths:
64
65 gcc -o hello_bson hello_bson.c $(pkg-config --libs --cflags libbson-1.0)
66
67
68 Or to statically link to libbson:
69
70 gcc -o hello_bson hello_bson.c $(pkg-config --libs --cflags libbson-static-1.0)
71
72
74 The bson_t structure
75 BSON documents are created using the bson_t structure. This structure
76 encapsulates the necessary logic for encoding using the BSON Specifica‐
77 tion. At the core, bson_t is a buffer manager and set of encoding rou‐
78 tines.
79
80 TIP:
81 BSON documents can live on the stack or the heap based on the per‐
82 formance needs or preference of the consumer.
83
84 Let's start by creating a new BSON document on the stack. Whenever us‐
85 ing libbson, make sure you #include <bson/bson.h>.
86
87 bson_t b;
88
89 bson_init (&b);
90
91 This creates an empty document. In JSON, this would be the same as {}.
92
93 We can now proceed to adding items to the BSON document. A variety of
94 functions prefixed with bson_append_ can be used based on the type of
95 field you want to append. Let's append a UTF-8 encoded string.
96
97 bson_append_utf8 (&b, "key", -1, "value", -1);
98
99 Notice the two -1 parameters. The first indicates that the length of
100 key in bytes should be determined with strlen(). Alternatively, we
101 could have passed the number 3. The same goes for the second -1, but
102 for value.
103
104 Libbson provides macros to make this less tedious when using string
105 literals. The following two appends are identical.
106
107 bson_append_utf8 (&b, "key", -1, "value", -1);
108 BSON_APPEND_UTF8 (&b, "key", "value");
109
110 Now let's take a look at an example that adds a few different field
111 types to a BSON document.
112
113 bson_t b = BSON_INITIALIZER;
114
115 BSON_APPEND_INT32 (&b, "a", 1);
116 BSON_APPEND_UTF8 (&b, "hello", "world");
117 BSON_APPEND_BOOL (&b, "bool", true);
118
119 Notice that we omitted the call to bson_init(). By specifying BSON_INI‐
120 TIALIZER we can remove the need to initialize the structure to a base
121 state.
122
123 Sub-Documents and Sub-Arrays
124 To simplify the creation of sub-documents and arrays,
125 bson_append_document_begin() and bson_append_array_begin() exist. These
126 can be used to build a sub-document using the parent documents memory
127 region as the destination buffer.
128
129 bson_t parent;
130 bson_t child;
131 char *str;
132
133 bson_init (&parent);
134 bson_append_document_begin (&parent, "foo", 3, &child);
135 bson_append_int32 (&child, "baz", 3, 1);
136 bson_append_document_end (&parent, &child);
137
138 str = bson_as_canonical_extended_json (&parent, NULL);
139 printf ("%s\n", str);
140 bson_free (str);
141
142 bson_destroy (&parent);
143
144 { "foo" : { "baz" : 1 } }
145
146 Simplified BSON C Object Notation
147 Creating BSON documents by hand can be tedious and time consuming.
148 BCON, or BSON C Object Notation, was added to allow for the creation of
149 BSON documents in a format that looks closer to the destination format.
150
151 The following example shows the use of BCON. Notice that values for
152 fields are wrapped in the BCON_* macros. These are required for the
153 variadic processor to determine the parameter type.
154
155 bson_t *doc;
156
157 doc = BCON_NEW ("foo",
158 "{",
159 "int",
160 BCON_INT32 (1),
161 "array",
162 "[",
163 BCON_INT32 (100),
164 "{",
165 "sub",
166 BCON_UTF8 ("value"),
167 "}",
168 "]",
169 "}");
170
171 Creates the following document
172
173 { "foo" : { "int" : 1, "array" : [ 100, { "sub" : "value" } ] } }
174
176 Description
177 Many libbson functions report errors by returning NULL or -1 and fill‐
178 ing out a bson_error_t structure with an error domain, error code, and
179 message.
180
181 • error.domain names the subsystem that generated the error.
182
183 • error.code is a domain-specific error type.
184
185 • error.message describes the error.
186
187 Some error codes overlap with others; always check both the domain and
188 code to determine the type of error.
189
190
191
192
193
194
195
196
197
198
199 ┌──────────────────┬─────────────────────┬──────────────────────────────────┐
200 │BSON_ERROR_JSON │ BSON_JSON_ER‐ │ bson_json_reader_t │
201 │ │ ROR_READ_CORRUPT_JS │ tried to parse in‐ │
202 │ │ BSON_JSON_ER‐ │ valid MongoDB Ex‐ │
203 │ │ ROR_READ_IN‐ │ tended JSON. Tried │
204 │ │ VALID_PARAM │ to parse a valid │
205 │ │ BSON_JSON_ER‐ │ JSON document that │
206 │ │ ROR_READ_CB_FAILURE │ is invalid as Mon‐ │
207 │ │ │ goDBExtended JSON. │
208 │ │ │ An internal call‐ │
209 │ │ │ back failure during │
210 │ │ │ JSON parsing. │
211 ├──────────────────┼─────────────────────┼──────────────────────────────────┤
212 │BSON_ERROR_READER │ BSON_ER‐ │ bson_json_reader_new_from_file() │
213 │ │ ROR_READER_BADFD │ could not open the │
214 │ │ │ file. │
215 └──────────────────┴─────────────────────┴──────────────────────────────────┘
216
218 Libbson provides a simple way to generate ObjectIDs. It can be used in
219 a single-threaded or multi-threaded manner depending on your require‐
220 ments.
221
222 The bson_oid_t structure represents an ObjectID in MongoDB. It is a
223 96-bit identifier.
224
225 Composition
226 • 4 bytes : The UNIX timestamp in big-endian format.
227
228 • 5 bytes : A random number.
229
230 • 3 bytes : A 24-bit monotonic counter incrementing from rand() in
231 big-endian.
232
233 Sorting ObjectIDs
234 The typical way to sort in C is using qsort(). Therefore, Libbson pro‐
235 vides a qsort() compatible callback function named bson_oid_compare().
236 It returns less than 1, greater than 1, or 0 depending on the equality
237 of two bson_oid_t structures.
238
239 Comparing Object IDs
240 If you simply want to compare two bson_oid_t structures for equality,
241 use bson_oid_equal().
242
243 Generating
244 To generate a bson_oid_t, you may use the following.
245
246 bson_oid_t oid;
247
248 bson_oid_init (&oid, NULL);
249
250 Parsing ObjectID Strings
251 You can also parse a string containing a bson_oid_t. The input string
252 MUST be 24 characters or more in length.
253
254 bson_oid_t oid;
255
256 bson_oid_init_from_string (&oid, "123456789012345678901234");
257
258 bson_oid_t oid;
259
260 bson_oid_init_from_string_unsafe (&oid, "123456789012345678901234");
261
262 Hashing ObjectIDs
263 If you need to store items in a hashtable, you may want to use the
264 bson_oid_t as the key. Libbson provides a hash function for just this
265 purpose. It is based on DJB hash.
266
267 unsigned hash;
268
269 hash = bson_oid_hash (oid);
270
271 Fetching ObjectID Creation Time
272 You can easily fetch the time that a bson_oid_t was generated using
273 bson_oid_get_time_t().
274
275 time_t t;
276
277 t = bson_oid_get_time_t (oid);
278 printf ("The OID was generated at %u\n", (unsigned) t);
279
281 Parsing
282 BSON documents are lazily parsed as necessary. To begin parsing a BSON
283 document, use one of the provided Libbson functions to create a new
284 bson_t from existing data such as bson_new_from_data(). This will make
285 a copy of the data so that additional mutations may occur to the BSON
286 document.
287
288 TIP:
289 If you only want to parse a BSON document and have no need to mutate
290 it, you may use bson_init_static() to avoid making a copy of the
291 data.
292
293 bson_t *b;
294
295 b = bson_new_from_data (my_data, my_data_len);
296 if (!b) {
297 fprintf (stderr, "The specified length embedded in <my_data> did not match "
298 "<my_data_len>\n");
299 return;
300 }
301
302 bson_destroy (b);
303
304 Only two checks are performed when creating a new bson_t from an exist‐
305 ing buffer. First, the document must begin with the buffer length,
306 matching what was expected by the caller. Second, the document must end
307 with the expected trailing \0 byte.
308
309 To parse the document further we use a bson_iter_t to iterate the ele‐
310 ments within the document. Let's print all of the field names in the
311 document.
312
313 bson_t *b;
314 bson_iter_t iter;
315
316 if ((b = bson_new_from_data (my_data, my_data_len))) {
317 if (bson_iter_init (&iter, b)) {
318 while (bson_iter_next (&iter)) {
319 printf ("Found element key: \"%s\"\n", bson_iter_key (&iter));
320 }
321 }
322 bson_destroy (b);
323 }
324
325 Converting a document to JSON uses a bson_iter_t and bson_visitor_t to
326 iterate all fields of a BSON document recursively and generate a UTF-8
327 encoded JSON string.
328
329 bson_t *b;
330 char *json;
331
332 if ((b = bson_new_from_data (my_data, my_data_len))) {
333 if ((json = bson_as_canonical_extended_json (b, NULL))) {
334 printf ("%s\n", json);
335 bson_free (json);
336 }
337 bson_destroy (b);
338 }
339
340 Recursing into Sub-Documents
341 Libbson provides convenient sub-iterators to dive down into a sub-docu‐
342 ment or sub-array. Below is an example that will dive into a sub-docu‐
343 ment named "foo" and print it's field names.
344
345 bson_iter_t iter;
346 bson_iter_t child;
347 char *json;
348
349 if (bson_iter_init_find (&iter, doc, "foo") &&
350 BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) {
351 while (bson_iter_next (&child)) {
352 printf ("Found sub-key of \"foo\" named \"%s\"\n",
353 bson_iter_key (&child));
354 }
355 }
356
357 Finding Fields using Dot Notation
358 Using the bson_iter_recurse() function exemplified above,
359 bson_iter_find_descendant() can find a field for you using the MongoDB
360 style path notation such as "foo.bar.0.baz".
361
362 Let's create a document like {"foo": {"bar": [{"baz: 1}]}} and locate
363 the "baz" field.
364
365 bson_t *b;
366 bson_iter_t iter;
367 bson_iter_t baz;
368
369 b =
370 BCON_NEW ("foo", "{", "bar", "[", "{", "baz", BCON_INT32 (1), "}", "]", "}");
371
372 if (bson_iter_init (&iter, b) &&
373 bson_iter_find_descendant (&iter, "foo.bar.0.baz", &baz) &&
374 BSON_ITER_HOLDS_INT32 (&baz)) {
375 printf ("baz = %d\n", bson_iter_int32 (&baz));
376 }
377
378 bson_destroy (b);
379
380 Validating a BSON Document
381 If all you want to do is validate that a BSON document is valid, you
382 can use bson_validate().
383
384 size_t err_offset;
385
386 if (!bson_validate (doc, BSON_VALIDATE_NONE, &err_offset)) {
387 fprintf (stderr,
388 "The document failed to validate at offset: %u\n",
389 (unsigned) err_offset);
390 }
391
392 See the bson_validate() documentation for more information and exam‐
393 ples.
394
396 Encoding
397 Libbson expects that you are always working with UTF-8 encoded text.
398 Anything else is invalid API use.
399
400 If you should need to walk through UTF-8 sequences, you can use the
401 various UTF-8 helper functions distributed with Libbson.
402
403 Validating a UTF-8 Sequence
404 To validate the string contained in my_string, use the following. You
405 may pass -1 for the string length if you know the string is NULL-termi‐
406 nated.
407
408 if (!bson_utf8_validate (my_string, -1, false)) {
409 printf ("Validation failed.\n");
410 }
411
412 If my_string has NULL bytes within the string, you must provide the
413 string length. Use the following format. Notice the true at the end in‐
414 dicating \0 is allowed.
415
416 if (!bson_utf8_validate (my_string, my_string_len, true)) {
417 printf ("Validation failed.\n");
418 }
419
420 For more information see the API reference for bson_utf8_validate().
421
423 MongoDB, Inc
424
426 2017-present, MongoDB, Inc
427
428
429
430
4311.23.1 Oct 20, 2022 BSON_TUTORIAL(3)