1MONGOC_CURSORS(3) libmongoc MONGOC_CURSORS(3)
2
3
4
6 mongoc_cursors - Cursors
7
9 Cursors exist on a MongoDB server. However, the mongoc_cursor_t struc‐
10 ture gives the local process a handle to the cursor. It is possible for
11 errors to occur on the server while iterating a cursor on the client.
12 Even a network partition may occur. This means that applications should
13 be robust in handling cursor failures.
14
15 While iterating cursors, you should check to see if an error has oc‐
16 curred. See the following example for how to robustly check for errors.
17
18 static void
19 print_all_documents (mongoc_collection_t *collection)
20 {
21 mongoc_cursor_t *cursor;
22 const bson_t *doc;
23 bson_error_t error;
24 bson_t query = BSON_INITIALIZER;
25 char *str;
26
27 cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);
28
29 while (mongoc_cursor_next (cursor, &doc)) {
30 str = bson_as_canonical_extended_json (doc, NULL);
31 printf ("%s\n", str);
32 bson_free (str);
33 }
34
35 if (mongoc_cursor_error (cursor, &error)) {
36 fprintf (stderr, "Failed to iterate all documents: %s\n", error.message);
37 }
38
39 mongoc_cursor_destroy (cursor);
40 }
41
43 The MongoDB C driver will automatically destroy a server-side cursor
44 when mongoc_cursor_destroy() is called. Failure to call this function
45 when done with a cursor will leak memory client side as well as consume
46 extra memory server side. If the cursor was configured to never time‐
47 out, it will become a memory leak on the server.
48
50 Tailable cursors are cursors that remain open even after they've re‐
51 turned a final result. This way, if more documents are added to a col‐
52 lection (i.e., to the cursor's result set), then you can continue to
53 call mongoc_cursor_next() to retrieve those additional results.
54
55 Here's a complete test case that demonstrates the use of tailable cur‐
56 sors.
57
58 NOTE:
59 Tailable cursors are for capped collections only.
60
61 An example to tail the oplog from a replica set.
62
63 mongoc-tail.c
64
65 #include <bson/bson.h>
66 #include <mongoc/mongoc.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69
70 #ifdef _WIN32
71 #define sleep(_n) Sleep ((_n) *1000)
72 #endif
73
74
75 static void
76 print_bson (const bson_t *b)
77 {
78 char *str;
79
80 str = bson_as_canonical_extended_json (b, NULL);
81 fprintf (stdout, "%s\n", str);
82 bson_free (str);
83 }
84
85
86 static mongoc_cursor_t *
87 query_collection (mongoc_collection_t *collection, uint32_t last_time)
88 {
89 mongoc_cursor_t *cursor;
90 bson_t query;
91 bson_t gt;
92 bson_t opts;
93
94 BSON_ASSERT (collection);
95
96 bson_init (&query);
97 BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", >);
98 BSON_APPEND_TIMESTAMP (>, "$gt", last_time, 0);
99 bson_append_document_end (&query, >);
100
101 bson_init (&opts);
102 BSON_APPEND_BOOL (&opts, "tailable", true);
103 BSON_APPEND_BOOL (&opts, "awaitData", true);
104
105 cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL);
106
107 bson_destroy (&query);
108 bson_destroy (&opts);
109
110 return cursor;
111 }
112
113
114 static void
115 tail_collection (mongoc_collection_t *collection)
116 {
117 mongoc_cursor_t *cursor;
118 uint32_t last_time;
119 const bson_t *doc;
120 bson_error_t error;
121 bson_iter_t iter;
122
123 BSON_ASSERT (collection);
124
125 last_time = (uint32_t) time (NULL);
126
127 while (true) {
128 cursor = query_collection (collection, last_time);
129 while (!mongoc_cursor_error (cursor, &error) &&
130 mongoc_cursor_more (cursor)) {
131 if (mongoc_cursor_next (cursor, &doc)) {
132 if (bson_iter_init_find (&iter, doc, "ts") &&
133 BSON_ITER_HOLDS_TIMESTAMP (&iter)) {
134 bson_iter_timestamp (&iter, &last_time, NULL);
135 }
136 print_bson (doc);
137 }
138 }
139 if (mongoc_cursor_error (cursor, &error)) {
140 if (error.domain == MONGOC_ERROR_SERVER) {
141 fprintf (stderr, "%s\n", error.message);
142 exit (1);
143 }
144 }
145
146 mongoc_cursor_destroy (cursor);
147 sleep (1);
148 }
149 }
150
151
152 int
153 main (int argc, char *argv[])
154 {
155 mongoc_collection_t *collection;
156 mongoc_client_t *client;
157 mongoc_uri_t *uri;
158 bson_error_t error;
159
160 if (argc != 2) {
161 fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]);
162 return EXIT_FAILURE;
163 }
164
165 mongoc_init ();
166
167 uri = mongoc_uri_new_with_error (argv[1], &error);
168 if (!uri) {
169 fprintf (stderr,
170 "failed to parse URI: %s\n"
171 "error message: %s\n",
172 argv[1],
173 error.message);
174 return EXIT_FAILURE;
175 }
176
177 client = mongoc_client_new_from_uri (uri);
178 if (!client) {
179 return EXIT_FAILURE;
180 }
181
182 mongoc_client_set_error_api (client, 2);
183
184 collection = mongoc_client_get_collection (client, "local", "oplog.rs");
185
186 tail_collection (collection);
187
188 mongoc_collection_destroy (collection);
189 mongoc_uri_destroy (uri);
190 mongoc_client_destroy (client);
191
192 return EXIT_SUCCESS;
193 }
194
195
196 Let's compile and run this example against a replica set to see updates
197 as they are made.
198
199 $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0)
200 $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet
201 {
202 "h" : -8458503739429355503,
203 "ns" : "test.test",
204 "o" : {
205 "_id" : {
206 "$oid" : "5372ab0a25164be923d10d50"
207 }
208 },
209 "op" : "i",
210 "ts" : {
211 "$timestamp" : {
212 "i" : 1,
213 "t" : 1400023818
214 }
215 },
216 "v" : 2
217 }
218
219 The line of output is a sample from performing db.test.insert({}) from
220 the mongo shell on the replica set.
221
222 See also mongoc_cursor_set_max_await_time_ms.
223
225 MongoDB, Inc
226
228 2017-present, MongoDB, Inc
229
230
231
232
2331.17.6 Jun 03, 2021 MONGOC_CURSORS(3)