.\" This manpage is Copyright (C) 2016 MongoDB, Inc. .\" .\" Permission is granted to copy, distribute and/or modify this document .\" under the terms of the GNU Free Documentation License, Version 1.3 .\" or any later version published by the Free Software Foundation; .\" with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. .\" A copy of the license is included in the section entitled "GNU .\" Free Documentation License". .\" .TH "CURSORS" "3" "2016\(hy10\(hy12" "MongoDB C Driver" .SH NAME Cursors \- None .SH "HANDLING CURSOR FAILURES" Cursors exist on a MongoDB server. However, the .B mongoc_cursor_t structure gives the local process a handle to the cursor. It is possible for errors to occur on the server while iterating a cursor on the client. Even a network partition may occur. This means that applications should be robust in handling cursor failures. While iterating cursors, you should check to see if an error has occurred. See the following example for how to robustly check for errors. .nf static void print_all_documents (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; const bson_t *doc; bson_error_t error; bson_t query = BSON_INITIALIZER; char *str; cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, NULL, NULL); while (mongoc_cursor_more (cursor) && mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); printf ("%s\en", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Failed to iterate all documents: %s\en", error.message); } mongoc_cursor_destroy (cursor); } .fi .SH "DESTROYING SERVER-SIDE CURSORS" The MongoDB C driver will automatically destroy a server\(hyside cursor when .B mongoc_cursor_destroy(3) is called. Failure to call this function when done with a cursor will leak memory client side as well as consume extra memory server side. If the cursor was configured to never timeout, it will become a memory leak on the server. .SH "TAILABLE CURSORS" Tailable cursors are cursors that remain open even after they've returned a final result. This way, if more documents are added to a collection (i.e., to the cursor's result set), then you can continue to call .B mongoc_cursor_next(3) to retrieve those additional results. Here's a complete test case that demonstrates the use of tailable cursors. .B NOTE .RS Note that tailable cursors are for capped collections only. .RE An example to tail the oplog from a replicaSet. .nf #include #include #include #include #ifdef _WIN32 #define sleep(_n) Sleep((_n) * 1000) #endif static void print_bson (const bson_t *b) { char *str; str = bson_as_json(b, NULL); fprintf(stdout, "%s\en", str); bson_free(str); } static mongoc_cursor_t * query_collection (mongoc_collection_t *collection, uint32_t last_time) { mongoc_cursor_t *cursor; bson_t query; bson_t gt; int fflags = (MONGOC_QUERY_TAILABLE_CURSOR | MONGOC_QUERY_AWAIT_DATA | MONGOC_QUERY_SLAVE_OK); BSON_ASSERT(collection); bson_init(&query); bson_append_document_begin(&query, "ts", 2, >); bson_append_timestamp(>, "$gt", 3, last_time, 0); bson_append_document_end(&query, >); cursor = mongoc_collection_find(collection, (mongoc_query_flags_t)fflags, 0, 0, 0, &query, NULL, NULL); bson_destroy(&query); return cursor; } static void tail_collection (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; uint32_t last_time; const bson_t *doc; bson_error_t error; bson_iter_t iter; BSON_ASSERT(collection); last_time = (uint32_t)time(NULL); while (true) { cursor = query_collection(collection, last_time); while (!mongoc_cursor_error(cursor, &error) && mongoc_cursor_more(cursor)) { if (mongoc_cursor_next(cursor, &doc)) { if (bson_iter_init_find(&iter, doc, "ts") && BSON_ITER_HOLDS_TIMESTAMP(&iter)) { bson_iter_timestamp(&iter, &last_time, NULL); } print_bson(doc); } } if (mongoc_cursor_error(cursor, &error)) { if (error.domain == MONGOC_ERROR_SERVER) { fprintf(stderr, "%s\en", error.message); exit(1); } } mongoc_cursor_destroy(cursor); sleep(1); } } int main (int argc, char *argv[]) { mongoc_collection_t *collection; mongoc_client_t *client; if (argc != 2) { fprintf(stderr, "usage: %s MONGO_URI\en", argv[0]); return EXIT_FAILURE; } mongoc_init(); client = mongoc_client_new(argv[1]); if (!client) { fprintf(stderr, "Invalid URI: \e"%s\e"\en", argv[1]); return EXIT_FAILURE; } mongoc_client_set_error_api (client, 2); collection = mongoc_client_get_collection(client, "local", "oplog.rs"); tail_collection(collection); mongoc_collection_destroy(collection); mongoc_client_destroy(client); return 0; } .fi Let's compile and run this example against a replica set to see updates as they are made. .B $ .B gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0) .B $ .B ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet .B { "ts" : { "$timestamp" : { "t" : 1400023818, "i" : 1 } }, "h" : -8458503739429355503, "v" : 2, "op" : "i", "ns" : "test.test", "o" : { "_id" : { "$oid" : "5372ab0a25164be923d10d50" } } } .B NOTE .RS The line of output is a sample from performing .B db.test.insert({}) from the mongo shell on the given replicaSet. .RE See also .B mongoc_cursor_set_max_await_time_ms . .B .SH COLOPHON This page is part of MongoDB C Driver. Please report any bugs at https://jira.mongodb.org/browse/CDRIVER.