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