libmongo-client 0.1.8
Loading...
Searching...
No Matches
Building BSON objects

Our first task will be to build a BSON document, which we can later insert into MongoDB. For this example, we want something more complex than a simple "Hello World"-style object, so we can showcase all the interesting functions of the BSON API.

Lets build a document that would look like this, if we were writing JSON:

{
  author: "Gergely Nagy",
  pages: [
    {
      title: "BSON tutorial",
      content: "...",
      importance: 1
    },
    {
      title: "Some other thing",
      content: "...",
      importance: 0
    }
  ],
  inline: true
}

First we start by including the main libmongo-client header. It's convenient to include the whole lot instead of including the used headers one by one, unless one's embedding only parts of the library.

#include <mongo.h>
#include <string.h>
#include <stdio.h>
int
main (void)
{

We'll be building the same BSON object in various different ways, so we declare a few more variables than we'd normally need.

bson *b_new, *b_builder, *b_builder_full;
bson *page1, *page2, *pages;

Next, we create the two pages:

page1 = bson_new ();
bson_append_string (page1, "title", "BSON tutorial", -1);
bson_append_string (page1, "content", "...", -1);
bson_append_int32 (page1, "importance", 1);
bson_finish (page1);
page2 = bson_new ();
bson_append_string (page2, "title", "Some other thing", -1);
bson_append_string (page2, "content", "...", -1);
bson_append_int32 (page2, "importance", 0);
bson_finish (page2);
gboolean bson_append_string(bson *b, const gchar *name, const gchar *val, gint32 length)
Append a string to a BSON object.
Definition bson.c:626
gboolean bson_append_int32(bson *b, const gchar *name, gint32 i)
Append a 32-bit integer to a BSON object.
Definition bson.c:761
bson * bson_new(void)
Create a new BSON object.
Definition bson.c:252
gboolean bson_finish(bson *b)
Finish a BSON object.
Definition bson.c:521

Then we construct the "pages" array. Do note how we set the key to "1" and "2", and how pages is just a document! This is because in BSON, an array is a document that has a special type, and where keys are numbers.

pages = bson_new ();
bson_append_document (pages, "1", page1);
bson_append_document (pages, "2", page2);
bson_finish (pages);
gboolean bson_append_document(bson *b, const gchar *name, const bson *doc)
Append a BSON document to a BSON object.
Definition bson.c:633

Finally, now that we have all the subdocuments ready, we build up our main object:

b_new = bson_new ();
bson_append_string (b_new, "author", "Gergely Nagy", -1);
bson_append_array (b_new, "pages", pages);
bson_append_boolean (b_new, "inline", TRUE);
bson_finish (b_new);
gboolean bson_append_array(bson *b, const gchar *name, const bson *array)
Append a BSON array to a BSON object.
Definition bson.c:639
gboolean bson_append_boolean(bson *b, const gchar *name, gboolean value)
Append a boolean to a BSON object.
Definition bson.c:675

And that's about it! But surely, there is an easier way to do this... And indeed, there is, using bson_build():

b_builder = bson_build (BSON_TYPE_STRING, "author", "Gergely Nagy", -1,
BSON_TYPE_ARRAY, "pages", pages,
BSON_TYPE_BOOLEAN, "inline", TRUE,
bson_finish (b_builder);
bson * bson_build(bson_type type, const gchar *name,...)
Build a BSON object in one go.
Definition bson.c:448
@ BSON_TYPE_ARRAY
4byte length + NULL terminated document
Definition bson.h:69
@ BSON_TYPE_STRING
4byte length + NULL terminated string
Definition bson.h:67
@ BSON_TYPE_NONE
Only used for errors.
Definition bson.h:65
@ BSON_TYPE_BOOLEAN
1byte boolean value
Definition bson.h:73

Much cleaner, but still, we had to create the pages array in three steps beforehand. Couldn't we do it in one gigantic function call instead?

b_builder_full = bson_build_full
(BSON_TYPE_STRING, "author", FALSE, "Gergely Nagy", -1,
BSON_TYPE_ARRAY, "pages", TRUE,
bson_build (BSON_TYPE_STRING, "title", "BSON tutorial", -1,
BSON_TYPE_STRING, "content", "...", -1,
BSON_TYPE_INT32, "importance", 1,
BSON_TYPE_DOCUMENT, "2", TRUE,
bson_build (BSON_TYPE_STRING, "title", "Some other thing", -1,
BSON_TYPE_STRING, "content", "...", -1,
BSON_TYPE_INT32, "importance", 0,
BSON_TYPE_BOOLEAN, "inline", FALSE, TRUE,
bson_finish (b_builder_full);
bson * bson_build_full(bson_type type, const gchar *name, gboolean free_after,...)
Build a BSON object in one go, with full control.
Definition bson.c:484
@ BSON_TYPE_DOCUMENT
4byte length + NULL terminated document
Definition bson.h:68
@ BSON_TYPE_INT32
4byte integer
Definition bson.h:84

Wonderful! We have three BSON objects created now, in three different ways! But are they the same? That's really easy to figure out. As a quick check, we can compare their sizes: if they do not match, we can bail out fast:

if (bson_size (b_new) != bson_size (b_builder) ||
bson_size (b_new) != bson_size (b_builder_full))
{
fprintf (stderr, "There's something fishy: the three BSON objects have different sizes");
return 1;
}
gint32 bson_size(const bson *b)
Return the size of a finished BSON object.
Definition bson.c:542

Or, we can do a more expensive comparsion, and compare the data:

if (memcmp (bson_data (b_new), bson_data (b_builder), bson_size (b_new)) != 0 ||
memcmp (bson_data (b_new), bson_data (b_builder_full), bson_size (b_new)) != 0)
{
fprintf (stderr, "The BSON objects do not match. Something smells.");
return 1;
}
const guint8 * bson_data(const bson *b)
Return the raw bytestream form of the BSON object.
Definition bson.c:554

And now that we are done, we free up the resources we allocated.

bson_free (b_builder_full);
bson_free (b_builder);
bson_free (b_new);
bson_free (pages);
bson_free (page2);
bson_free (page1);
void bson_free(bson *b)
Free the memory associated with a BSON object.
Definition bson.c:579
return 0;
}