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
85 using 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, bson_append_docu‐
125 ment_begin() and bson_append_array_begin() exist. These can be used to
126 build a sub-document using the parent documents memory region as the
127 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_ERROR_READ_COR‐ │ bson_json_reader_t │
201│ │ RUPT_JS │ tried to parse │
202│ │ BSON_JSON_ERROR_READ_INVALID_PARAM │ invalid MongoDB │
203│ │ BSON_JSON_ERROR_READ_CB_FAIL‐ │ Extended JSON. │
204│ │ URE │ Tried to parse a │
205│ │ │ valid JSON document │
206│ │ │ that is invalid as │
207│ │ │ MongoDBExtended │
208│ │ │ JSON. An internal │
209│ │ │ callback failure │
210│ │ │ during JSON pars‐ │
211│ │ │ ing. │
212├──────────────────┼────────────────────────────────────┼────────────────────────────────┤
213│BSON_ERROR_READER │ BSON_ERROR_READER_BADFD │ bson_json_reader_new_from_file │
214│ │ │ could not open the │
215│ │ │ file. │
216└──────────────────┴────────────────────────────────────┴────────────────────────────────┘
217
219 Libbson provides a simple way to generate ObjectIDs. It can be used in
220 a single-threaded or multi-threaded manner depending on your require‐
221 ments.
222
223 The bson_oid_t structure represents an ObjectID in MongoDB. It is a
224 96-bit identifier.
225
226 Composition
227 · 4 bytes : The UNIX timestamp in big-endian format.
228
229 · 5 bytes : A random number.
230
231 · 3 bytes : A 24-bit monotonic counter incrementing from rand() in
232 big-endian.
233
234 Sorting ObjectIDs
235 The typical way to sort in C is using qsort(). Therefore, Libbson pro‐
236 vides a qsort() compatible callback function named bson_oid_compare().
237 It returns less than 1, greater than 1, or 0 depending on the equality
238 of two bson_oid_t structures.
239
240 Comparing Object IDs
241 If you simply want to compare two bson_oid_t structures for equality,
242 use bson_oid_equal().
243
244 Generating
245 To generate a bson_oid_t, you may use the following.
246
247 bson_oid_t oid;
248
249 bson_oid_init (&oid, NULL);
250
251 Parsing ObjectID Strings
252 You can also parse a string containing a bson_oid_t. The input string
253 MUST be 24 characters or more in length.
254
255 bson_oid_t oid;
256
257 bson_oid_init_from_string (&oid, "123456789012345678901234");
258
259 bson_oid_t oid;
260
261 bson_oid_init_from_string_unsafe (&oid, "123456789012345678901234");
262
263 Hashing ObjectIDs
264 If you need to store items in a hashtable, you may want to use the
265 bson_oid_t as the key. Libbson provides a hash function for just this
266 purpose. It is based on DJB hash.
267
268 unsigned hash;
269
270 hash = bson_oid_hash (oid);
271
272 Fetching ObjectID Creation Time
273 You can easily fetch the time that a bson_oid_t was generated using
274 bson_oid_get_time_t().
275
276 time_t t;
277
278 t = bson_oid_get_time_t (oid);
279 printf ("The OID was generated at %u\n", (unsigned) t);
280
282 Parsing
283 BSON documents are lazily parsed as necessary. To begin parsing a BSON
284 document, use one of the provided Libbson functions to create a new
285 bson_t from existing data such as bson_new_from_data(). This will make
286 a copy of the data so that additional mutations may occur to the BSON
287 document.
288
289 TIP:
290 If you only want to parse a BSON document and have no need to mutate
291 it, you may use bson_init_static() to avoid making a copy of the
292 data.
293
294 bson_t *b;
295
296 b = bson_new_from_data (my_data, my_data_len);
297 if (!b) {
298 fprintf (stderr, "The specified length embedded in <my_data> did not match "
299 "<my_data_len>\n");
300 return;
301 }
302
303 bson_destroy (b);
304
305 Only two checks are performed when creating a new bson_t from an exist‐
306 ing buffer. First, the document must begin with the buffer length,
307 matching what was expected by the caller. Second, the document must end
308 with the expected trailing \0 byte.
309
310 To parse the document further we use a bson_iter_t to iterate the ele‐
311 ments within the document. Let's print all of the field names in the
312 document.
313
314 bson_t *b;
315 bson_iter_t iter;
316
317 if ((b = bson_new_from_data (my_data, my_data_len))) {
318 if (bson_iter_init (&iter, b)) {
319 while (bson_iter_next (&iter)) {
320 printf ("Found element key: \"%s\"\n", bson_iter_key (&iter));
321 }
322 }
323 bson_destroy (b);
324 }
325
326 Converting a document to JSON uses a bson_iter_t and bson_visitor_t to
327 iterate all fields of a BSON document recursively and generate a UTF-8
328 encoded JSON string.
329
330 bson_t *b;
331 char *json;
332
333 if ((b = bson_new_from_data (my_data, my_data_len))) {
334 if ((json = bson_as_canonical_extended_json (b, NULL))) {
335 printf ("%s\n", json);
336 bson_free (json);
337 }
338 bson_destroy (b);
339 }
340
341 Recursing into Sub-Documents
342 Libbson provides convenient sub-iterators to dive down into a sub-docu‐
343 ment or sub-array. Below is an example that will dive into a sub-docu‐
344 ment named "foo" and print it's field names.
345
346 bson_iter_t iter;
347 bson_iter_t child;
348 char *json;
349
350 if (bson_iter_init_find (&iter, doc, "foo") &&
351 BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) {
352 while (bson_iter_next (&child)) {
353 printf ("Found sub-key of \"foo\" named \"%s\"\n",
354 bson_iter_key (&child));
355 }
356 }
357
358 Finding Fields using Dot Notation
359 Using the bson_iter_recurse() function exemplified above,
360 bson_iter_find_descendant() can find a field for you using the MongoDB
361 style path notation such as "foo.bar.0.baz".
362
363 Let's create a document like {"foo": {"bar": [{"baz: 1}]}} and locate
364 the "baz" field.
365
366 bson_t *b;
367 bson_iter_t iter;
368 bson_iter_t baz;
369
370 b =
371 BCON_NEW ("foo", "{", "bar", "[", "{", "baz", BCON_INT32 (1), "}", "]", "}");
372
373 if (bson_iter_init (&iter, b) &&
374 bson_iter_find_descendant (&iter, "foo.bar.0.baz", &baz) &&
375 BSON_ITER_HOLDS_INT32 (&baz)) {
376 printf ("baz = %d\n", bson_iter_int32 (&baz));
377 }
378
379 bson_destroy (b);
380
381 Validating a BSON Document
382 If all you want to do is validate that a BSON document is valid, you
383 can use bson_validate().
384
385 size_t err_offset;
386
387 if (!bson_validate (doc, BSON_VALIDATE_NONE, &err_offset)) {
388 fprintf (stderr,
389 "The document failed to validate at offset: %u\n",
390 (unsigned) err_offset);
391 }
392
393 See the bson_validate() documentation for more information and exam‐
394 ples.
395
397 Encoding
398 Libbson expects that you are always working with UTF-8 encoded text.
399 Anything else is invalid API use.
400
401 If you should need to walk through UTF-8 sequences, you can use the
402 various UTF-8 helper functions distributed with Libbson.
403
404 Validating a UTF-8 Sequence
405 To validate the string contained in my_string, use the following. You
406 may pass -1 for the string length if you know the string is NULL-termi‐
407 nated.
408
409 if (!bson_utf8_validate (my_string, -1, false)) {
410 printf ("Validation failed.\n");
411 }
412
413 If my_string has NULL bytes within the string, you must provide the
414 string length. Use the following format. Notice the true at the end
415 indicating \0 is allowed.
416
417 if (!bson_utf8_validate (my_string, my_string_len, true)) {
418 printf ("Validation failed.\n");
419 }
420
421 For more information see the API reference for bson_utf8_validate().
422
424 MongoDB, Inc
425
427 2017-present, MongoDB, Inc
428
429
430
431
4321.17.4 Feb 04, 2021 BSON_TUTORIAL(3)