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