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