zodiac2k's Blog

MongDB über Mongo C-Driver

Programmierung > C/C++

Da es im Web nur sehr wenige Beispiele zur Implementation der Mongo C-Driver gibt, möchte ich hier ein Tutorial anbieten, dass übersichtlich ist, aber dennoch genug Details enthält. Für dieses Tutorial setze ich Grundkenntnisse in Linux, C und MongoDB vorraus!

Zuerst müssen die benötigten Pakete installiert werden und die Treiber heruntergeladen werden. Die Kommandos stammen hier von einem Ubuntu LTS 14:

$ sudo apt-get install pkg-config libssl-dev libsasl2-dev
$ wget https://github.com/mongodb/mongo-c-driver/releases/download/1.3.0/mongo-c-driver-1.3.0.tar.gz $ tar xzf mongo-c-driver-1.3.0.tar.gz $ cd mongo-c-driver-1.3.0 $ ./configure $ make $ sudo make install $ ldconfig

Zuallerst muss die Verbindung zur Datenbank über den Client hergestellt werden. Dann kann sich auf eine Collection verbunden werden. Diese können bei MongoDB, im Gegensetz zu SQL Datenbanken, sofort verwendet werden und müssen nicht erst erstellt werden.

#include <bson.h>
#include <mongoc.h>

mongoc_client_t *client;
mongoc_collection_t *collection;

mongoc_init(); client = mongoc_client_new("mongodb://localhost:27017/"); collection = mongoc_client_get_collection(client, "mydb", "mycollection");

Einen Datensatz einfügen ist einfach. Es muss ein Dokument mit bson_new() erzeugt werden, dem alle Attribute, Arrays und Objekte über die APPEND_ Methoden hinzugefügt werden. Anschließend wird der Insert durchgeführt, und Fehler wie unten gezeigt, abgefangen.
Wenn das Dokument kein Attribut namens "_id" enthält, generiert die Datenbank eine einmalige Dokumenten-ID:

#include <time.h>

bson_error_t error;
bson_t *doc;
doc = bson_new();

timeval tv;
gettimeofday (&tv, NULL);

//add different attributes to document BSON_APPEND_INT32 (doc, "mynumber", 12345678 ); BSON_APPEND_DOUBLE (doc, "mydouble", 1234.5678 ); BSON_APPEND_UTF8 (doc, "mystring", "Hallo Welt"); BSON_APPEND_TIMEVAL(doc, "mytime", &tv ); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { fprintf (stderr, "%s\n", error.message); } bson_destroy(doc);

Man kann die OID,wie oben beschrieben, aber auch Client-seitig erzeugen. Und so kann man sie als String auch auslesen:

bson_oid_t oid;
bson_oid_init (&oid, NULL);

char oidstr[26];
bson_oid_to_string( &oid, &oidstr );

Ähnlich simpel ist auch die Abfrage von Objekten. Man muss ein Query-Objekt erstellen, dass die Suchbedingungen enthält. In diesem Fall wird nach einer bestimmten Dokumenten-ID gesucht. Über das Cursor-Objekt kann man durch die Ergebnisse iterieren. In diesem Fall sollte maximal ein Datensatz als Ergebnis rauskommen. Anschließend müssen die allokierten Objekte wieder freigegeben werden:

const bson_t *doc;
bson_iter_t it;
const bson_value_t *value;
char *str;

//OID Objekt erzeugen und die ID setzen
bson_oid_t oid;
bson_oid_init_from_string(&oid, "Objekt-ID");

//Query erstellen und OID setzen
bson_t *query;
query = bson_new();
BSON_APPEND_OID(query, "_id", &oid);

//Cursor für Ergebnisse erzeugen
mongoc_cursor_t *cursor;	
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL);

//durch die Ergebnisse iterieren
if ( mongoc_cursor_next(cursor, &doc) ) {
    str = bson_as_json (doc, NULL);
    printf ("%s\n", str);
    bson_free(str);

    //Werte auslesen
    if ( bson_iter_init(&it, doc) && bson_iter_find(&it, "_id") ) {
        value = bson_iter_value(&it);
        char* myoid = new char[26];
        bson_oid_to_string ( &value->value.v_oid, myoid );
        delete[] myoid;
    }
    if ( bson_iter_init(&it, doc) && bson_iter_find(&it, "myint") ) {
        value = bson_iter_value(&it);
        int myint = value->value.v_int32;
    }
    if ( bson_iter_init(&it, doc) && bson_iter_find(&it, "mystring") ) {
        value = bson_iter_value(&it);
        char* mystring = new char[value->value.v_utf8.len + 1];
        strcpy( mystring, value->value.v_utf8.str );
        delete[] mystring;
    }
    if ( bson_iter_init(&it, doc) && bson_iter_find(&it, "mydouble") ) {
        value = bson_iter_value(&it);
        double mydouble = value->value.v_double;
    }
    if ( bson_iter_init(&it, doc) && bson_iter_find(&it, "mytime") ) {
        value = bson_iter_value(&it);
        timeval tv;
        tv.tv_sec  = value->value.v_datetime / 1000;
        tv.tv_usec = value->value.v_datetime % 1000;
    }
}

//Cursur und Query freigeben
mongoc_cursor_destroy(cursor);
bson_destroy(query);

Klassische Updates können ebenfalls sehr einfach umgesetzt werden. Ein Dokument, das über die Objekt-ID identifiziert wird, wird aktualisiert und der Zeitstempel "mytime" wird überschrieben. Updates verändert nur die Attributen, die über das doc überschrieben werden. MongoDB bietet aber auch Replace-Funktionen, die das Objekt komplett ersetzen können.

bson_error_t error;

//OID setzen
bson_oid_t oid;
bson_oid_init_from_string(&oid, "Objekt-ID");
	
//Query zum identifizieren der zu aktualisierenden Datensätze
bson_t *query;
query = bson_new();
BSON_APPEND_OID(query, "_id", &oid);

//Neuer Zeitstempel
timeval tv;
gettimeofday (&tv, NULL);

//Erstelle Dokuemnt mit den zu aktualisierenden Werten
bson_t *doc;
doc = bson_new();
BSON_APPEND_TIMEVAL(doc, "mytime", &tv);
	
//Erstelle Update Objekt
bson_t *update;
update = bson_new();
BSON_APPEND_DOCUMENT( update, "$set", doc );

//Update ausführen
if (!mongoc_collection_update (collection, MONGOC_UPDATE_NONE, query, update, NULL, &error)) {
    fprintf (stderr, "%s\n", error.message);
}

//Allokierte Objekte wieder freigeben
bson_destroy(query);
bson_destroy(doc);
bson_destroy(update);
Als weitere Referenz kann ich hier noch die Libbson API empfehlen:
https://api.mongodb.org/libbson/current/

Verfasst am 23.02.2016