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