.\" Man page generated from reStructuredText. . .TH "BSON_TUTORIAL" "3" "Feb 23, 2019" "1.14.0" "Libbson" .SH NAME bson_tutorial \- Tutorial . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH USING LIBBSON IN YOUR C PROGRAM .SS Include bson.h .sp All libbson\(aqs functions and types are available in one header file. Simply include \fBbson.h\fP: hello_bson.c.INDENT 0.0 .INDENT 3.5 .sp .nf .ft C #include #include int main (int argc, const char **argv) { bson_t *b; char *j; b = BCON_NEW ("hello", BCON_UTF8 ("bson!")); j = bson_as_canonical_extended_json (b, NULL); printf ("%s\en", j); bson_free (j); bson_destroy (b); return 0; } .ft P .fi .UNINDENT .UNINDENT .SS CMake .sp The libbson installation includes a \fI\%CMake config\-file package\fP, so you can use CMake\(aqs \fI\%find_package\fP command to find libbson\(aqs header and library paths and link to libbson: CMakeLists.txt.INDENT 0.0 .INDENT 3.5 .sp .nf .ft C # Specify the minimum version you require. find_package (libbson\-1.0 1.7 REQUIRED) message ("\-\- libbson found version \e"${BSON_VERSION}\e"") message ("\-\- libbson include path \e"${BSON_INCLUDE_DIRS}\e"") message ("\-\- libbson libraries \e"${BSON_LIBRARIES}\e"") # The "hello_bson.c" sample program is shared among four tests. add_executable (hello_bson ../../hello_bson.c) target_include_directories (hello_bson PRIVATE ${BSON_INCLUDE_DIRS}) target_link_libraries (hello_bson PRIVATE ${BSON_LIBRARIES}) target_compile_definitions (hello_bson PRIVATE ${BSON_DEFINITIONS}) .ft P .fi .UNINDENT .UNINDENT .sp By default, libbson is dynamically linked. You can use libbson as a static library instead: Use the included \fBlibbson\-static\-1.0\fP config\-file package and (on Unix) link to \fBpthread\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C # Specify the minimum version you require. find_package (libbson\-static\-1.0 1.7 REQUIRED) message ("\-\- libbson\-static found version \e"${BSON_STATIC_VERSION}\e"") message ("\-\- libbson\-static include path \e"${BSON_STATIC_INCLUDE_DIRS}\e"") message ("\-\- libbson\-static libraries \e"${BSON_STATIC_LIBRARIES}\e"") # The "hello_bson.c" sample program is shared among four tests. add_executable (hello_bson ../../hello_bson.c) target_include_directories (hello_bson PRIVATE ${BSON_STATIC_INCLUDE_DIRS}) target_link_libraries (hello_bson PRIVATE ${BSON_STATIC_LIBRARIES}) target_compile_definitions (hello_bson PRIVATE ${BSON_STATIC_DEFINITIONS}) .ft P .fi .UNINDENT .UNINDENT .SS pkg\-config .sp If you\(aqre not using CMake, use \fI\%pkg\-config\fP on the command line to set header and library paths: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C gcc \-o hello_bson hello_bson.c $(pkg\-config \-\-libs \-\-cflags libbson\-1.0) .ft P .fi .UNINDENT .UNINDENT .sp Or to statically link to libbson: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C gcc \-o hello_bson hello_bson.c $(pkg\-config \-\-libs \-\-cflags libbson\-static\-1.0) .ft P .fi .UNINDENT .UNINDENT .SH CREATING A BSON DOCUMENT .SS The bson_t structure .sp BSON documents are created using the \fBbson_t\fP structure. This structure encapsulates the necessary logic for encoding using the \fI\%BSON Specification\fP\&. At the core, \fBbson_t\fP is a buffer manager and set of encoding routines. .sp \fBTIP:\fP .INDENT 0.0 .INDENT 3.5 BSON documents can live on the stack or the heap based on the performance needs or preference of the consumer. .UNINDENT .UNINDENT .sp Let\(aqs start by creating a new BSON document on the stack. Whenever using libbson, make sure you \fB#include \fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t b; bson_init (&b); .ft P .fi .UNINDENT .UNINDENT .sp This creates an empty document. In JSON, this would be the same as \fB{}\fP\&. .sp We can now proceed to adding items to the BSON document. A variety of functions prefixed with \fBbson_append_\fP can be used based on the type of field you want to append. Let\(aqs append a UTF\-8 encoded string. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_append_utf8 (&b, "key", \-1, "value", \-1); .ft P .fi .UNINDENT .UNINDENT .sp Notice the two \fB\-1\fP parameters. The first indicates that the length of \fBkey\fP in bytes should be determined with \fBstrlen()\fP\&. Alternatively, we could have passed the number \fB3\fP\&. The same goes for the second \fB\-1\fP, but for \fBvalue\fP\&. .sp Libbson provides macros to make this less tedious when using string literals. The following two appends are identical. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_append_utf8 (&b, "key", \-1, "value", \-1); BSON_APPEND_UTF8 (&b, "key", "value"); .ft P .fi .UNINDENT .UNINDENT .sp Now let\(aqs take a look at an example that adds a few different field types to a BSON document. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t b = BSON_INITIALIZER; BSON_APPEND_INT32 (&b, "a", 1); BSON_APPEND_UTF8 (&b, "hello", "world"); BSON_APPEND_BOOL (&b, "bool", true); .ft P .fi .UNINDENT .UNINDENT .sp Notice that we omitted the call to \fBbson_init()\fP\&. By specifying \fBBSON_INITIALIZER\fP we can remove the need to initialize the structure to a base state. .SS Sub\-Documents and Sub\-Arrays .sp To simplify the creation of sub\-documents and arrays, \fBbson_append_document_begin()\fP and \fBbson_append_array_begin()\fP exist. These can be used to build a sub\-document using the parent documents memory region as the destination buffer. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t parent; bson_t child; char *str; bson_init (&parent); bson_append_document_begin (&parent, "foo", 3, &child); bson_append_int32 (&child, "baz", 3, 1); bson_append_document_end (&parent, &child); str = bson_as_canonical_extended_json (&parent, NULL); printf ("%s\en", str); bson_free (str); bson_destroy (&parent); .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C { "foo" : { "baz" : 1 } } .ft P .fi .UNINDENT .UNINDENT .SS Simplified BSON C Object Notation .sp Creating BSON documents by hand can be tedious and time consuming. BCON, or BSON C Object Notation, was added to allow for the creation of BSON documents in a format that looks closer to the destination format. .sp The following example shows the use of BCON. Notice that values for fields are wrapped in the \fBBCON_*\fP macros. These are required for the variadic processor to determine the parameter type. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t *doc; doc = BCON_NEW ("foo", "{", "int", BCON_INT32 (1), "array", "[", BCON_INT32 (100), "{", "sub", BCON_UTF8 ("value"), "}", "]", "}"); .ft P .fi .UNINDENT .UNINDENT .sp Creates the following document .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C { "foo" : { "int" : 1, "array" : [ 100, { "sub" : "value" } ] } } .ft P .fi .UNINDENT .UNINDENT .SH HANDLING ERRORS .SS Description .sp Many libbson functions report errors by returning \fBNULL\fP or \-1 and filling out a \fBbson_error_t\fP structure with an error domain, error code, and message. .INDENT 0.0 .IP \(bu 2 \fBerror.domain\fP names the subsystem that generated the error. .IP \(bu 2 \fBerror.code\fP is a domain\-specific error type. .IP \(bu 2 \fBerror.message\fP describes the error. .UNINDENT .sp Some error codes overlap with others; always check both the domain and code to determine the type of error. .TS center; |l|l|l|. _ T{ \fBBSON_ERROR_JSON\fP T} T{ \fBBSON_JSON_ERROR_READ_CORRUPT_JS\fP \fBBSON_JSON_ERROR_READ_INVALID_PARAM\fP \fBBSON_JSON_ERROR_READ_CB_FAILURE\fP T} T{ \fBbson_json_reader_t\fP tried to parse invalid MongoDB Extended JSON. Tried to parse a valid JSON document that is invalid as MongoDBExtended JSON. An internal callback failure during JSON parsing. T} _ T{ \fBBSON_ERROR_READER\fP T} T{ \fBBSON_ERROR_READER_BADFD\fP T} T{ \fBbson_json_reader_new_from_file\fP could not open the file. T} _ .TE .SH OBJECTIDS .sp Libbson provides a simple way to generate ObjectIDs. It can be used in a single\-threaded or multi\-threaded manner depending on your requirements. .sp The \fBbson_oid_t\fP structure represents an \fBObjectID\fP in MongoDB. It is a 96\-bit identifier. .SS Composition .INDENT 0.0 .IP \(bu 2 4 bytes : The UNIX timestamp in big\-endian format. .IP \(bu 2 5 bytes : A random number. .IP \(bu 2 3 bytes : A 24\-bit monotonic counter incrementing from \fBrand()\fP in big\-endian. .UNINDENT .SS Sorting ObjectIDs .sp The typical way to sort in C is using \fBqsort()\fP\&. Therefore, Libbson provides a \fBqsort()\fP compatible callback function named \fBbson_oid_compare()\fP\&. It returns \fBless than 1\fP, \fBgreater than 1\fP, or \fB0\fP depending on the equality of two \fBbson_oid_t\fP structures. .SS Comparing Object IDs .sp If you simply want to compare two \fBbson_oid_t\fP structures for equality, use \fBbson_oid_equal()\fP\&. .SS Generating .sp To generate a \fBbson_oid_t\fP, you may use the following. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_oid_t oid; bson_oid_init (&oid, NULL); .ft P .fi .UNINDENT .UNINDENT .SS Parsing ObjectID Strings .sp You can also parse a string containing a \fBbson_oid_t\fP\&. The input string \fIMUST\fP be 24 characters or more in length. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_oid_t oid; bson_oid_init_from_string (&oid, "123456789012345678901234"); .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_oid_t oid; bson_oid_init_from_string_unsafe (&oid, "123456789012345678901234"); .ft P .fi .UNINDENT .UNINDENT .SS Hashing ObjectIDs .sp If you need to store items in a hashtable, you may want to use the \fBbson_oid_t\fP as the key. Libbson provides a hash function for just this purpose. It is based on DJB hash. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C unsigned hash; hash = bson_oid_hash (oid); .ft P .fi .UNINDENT .UNINDENT .SS Fetching ObjectID Creation Time .sp You can easily fetch the time that a \fBbson_oid_t\fP was generated using \fBbson_oid_get_time_t()\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C time_t t; t = bson_oid_get_time_t (oid); printf ("The OID was generated at %u\en", (unsigned) t); .ft P .fi .UNINDENT .UNINDENT .SH PARSING AND ITERATING BSON DOCUMENTS .SS Parsing .sp BSON documents are lazily parsed as necessary. To begin parsing a BSON document, use one of the provided Libbson functions to create a new \fBbson_t\fP from existing data such as \fBbson_new_from_data()\fP\&. This will make a copy of the data so that additional mutations may occur to the BSON document. .sp \fBTIP:\fP .INDENT 0.0 .INDENT 3.5 If you only want to parse a BSON document and have no need to mutate it, you may use \fBbson_init_static()\fP to avoid making a copy of the data. .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t *b; b = bson_new_from_data (my_data, my_data_len); if (!b) { fprintf (stderr, "The specified length embedded in did not match " "\en"); return; } bson_destroy (b); .ft P .fi .UNINDENT .UNINDENT .sp Only two checks are performed when creating a new \fBbson_t\fP from an existing buffer. First, the document must begin with the buffer length, matching what was expected by the caller. Second, the document must end with the expected trailing \fB\e0\fP byte. .sp To parse the document further we use a \fBbson_iter_t\fP to iterate the elements within the document. Let\(aqs print all of the field names in the document. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t *b; bson_iter_t iter; if ((b = bson_new_from_data (my_data, my_data_len))) { if (bson_iter_init (&iter, b)) { while (bson_iter_next (&iter)) { printf ("Found element key: \e"%s\e"\en", bson_iter_key (&iter)); } } bson_destroy (b); } .ft P .fi .UNINDENT .UNINDENT .sp Converting a document to JSON uses a \fBbson_iter_t\fP and \fBbson_visitor_t\fP to iterate all fields of a BSON document recursively and generate a UTF\-8 encoded JSON string. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t *b; char *json; if ((b = bson_new_from_data (my_data, my_data_len))) { if ((json = bson_as_canonical_extended_json (b, NULL))) { printf ("%s\en", json); bson_free (json); } bson_destroy (b); } .ft P .fi .UNINDENT .UNINDENT .SS Recursing into Sub\-Documents .sp Libbson provides convenient sub\-iterators to dive down into a sub\-document or sub\-array. Below is an example that will dive into a sub\-document named "foo" and print it\(aqs field names. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_iter_t iter; bson_iter_t child; char *json; if (bson_iter_init_find (&iter, doc, "foo") && BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) { while (bson_iter_next (&child)) { printf ("Found sub\-key of \e"foo\e" named \e"%s\e"\en", bson_iter_key (&child)); } } .ft P .fi .UNINDENT .UNINDENT .SS Finding Fields using Dot Notation .sp Using the \fBbson_iter_recurse()\fP function exemplified above, \fBbson_iter_find_descendant()\fP can find a field for you using the MongoDB style path notation such as "foo.bar.0.baz". .sp Let\(aqs create a document like \fB{"foo": {"bar": [{"baz: 1}]}}\fP and locate the \fB"baz"\fP field. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C bson_t *b; bson_iter_t iter; bson_iter_t baz; b = BCON_NEW ("foo", "{", "bar", "[", "{", "baz", BCON_INT32 (1), "}", "]", "}"); if (bson_iter_init (&iter, b) && bson_iter_find_descendant (&iter, "foo.bar.0.baz", &baz) && BSON_ITER_HOLDS_INT32 (&baz)) { printf ("baz = %d\en", bson_iter_int32 (&baz)); } bson_destroy (b); .ft P .fi .UNINDENT .UNINDENT .SS Validating a BSON Document .sp If all you want to do is validate that a BSON document is valid, you can use \fBbson_validate()\fP\&. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C size_t err_offset; if (!bson_validate (doc, BSON_VALIDATE_NONE, &err_offset)) { fprintf (stderr, "The document failed to validate at offset: %u\en", (unsigned) err_offset); } .ft P .fi .UNINDENT .UNINDENT .sp See the \fBbson_validate()\fP documentation for more information and examples. .SH UTF-8 .SS Encoding .sp Libbson expects that you are always working with UTF\-8 encoded text. Anything else is \fBinvalid API use\fP\&. .sp If you should need to walk through UTF\-8 sequences, you can use the various UTF\-8 helper functions distributed with Libbson. .SS Validating a UTF\-8 Sequence .sp To validate the string contained in \fBmy_string\fP, use the following. You may pass \fB\-1\fP for the string length if you know the string is NULL\-terminated. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C if (!bson_utf8_validate (my_string, \-1, false)) { printf ("Validation failed.\en"); } .ft P .fi .UNINDENT .UNINDENT .sp If \fBmy_string\fP has NULL bytes within the string, you must provide the string length. Use the following format. Notice the \fBtrue\fP at the end indicating \fB\e0\fP is allowed. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C if (!bson_utf8_validate (my_string, my_string_len, true)) { printf ("Validation failed.\en"); } .ft P .fi .UNINDENT .UNINDENT .sp For more information see the API reference for \fBbson_utf8_validate()\fP\&. .SH AUTHOR MongoDB, Inc .SH COPYRIGHT 2017-present, MongoDB, Inc .\" Generated by docutils manpage writer. .