1MONGOC_GUIDES(3) MongoDB C Driver MONGOC_GUIDES(3)
2
3
4
6 mongoc_guides - Guides
7
9 Drivers for some other languages provide helper functions to perform
10 certain common tasks. In the C Driver we must explicitly build commands
11 to send to the server.
12
13 This snippet contains example code for the explain, copydb and
14 cloneCollection commands.
15
16 Setup
17 First we'll write some code to insert sample data: doc-com‐
18 mon-insert.c.INDENT 0.0
19
20 /* Don't try to compile this file on its own. It's meant to be #included
21 by example code */
22
23 /* Insert some sample data */
24 bool
25 insert_data (mongoc_collection_t *collection)
26 {
27 mongoc_bulk_operation_t *bulk;
28 enum N { ndocs = 4 };
29 bson_t *docs[ndocs];
30 bson_error_t error;
31 int i = 0;
32 bool ret;
33
34 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
35
36 docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
37 docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
38 docs[2] = BCON_NEW (
39 "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
40 docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
41
42 for (i = 0; i < ndocs; i++) {
43 mongoc_bulk_operation_insert (bulk, docs[i]);
44 bson_destroy (docs[i]);
45 docs[i] = NULL;
46 }
47
48 ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
49
50 if (!ret) {
51 fprintf (stderr, "Error inserting data: %s\n", error.message);
52 }
53
54 mongoc_bulk_operation_destroy (bulk);
55 return ret;
56 }
57
58 /* A helper which we'll use a lot later on */
59 void
60 print_res (const bson_t *reply)
61 {
62 char *str;
63 BSON_ASSERT (reply);
64 str = bson_as_canonical_extended_json (reply, NULL);
65 printf ("%s\n", str);
66 bson_free (str);
67 }
68
69
70 explain Command
71 This is how to use the explain command in MongoDB 3.2+:
72 explain.c.INDENT 0.0
73
74 bool
75 explain (mongoc_collection_t *collection)
76 {
77 bson_t *command;
78 bson_t reply;
79 bson_error_t error;
80 bool res;
81
82 command = BCON_NEW ("explain",
83 "{",
84 "find",
85 BCON_UTF8 (COLLECTION_NAME),
86 "filter",
87 "{",
88 "x",
89 BCON_INT32 (1),
90 "}",
91 "}");
92 res = mongoc_collection_command_simple (
93 collection, command, NULL, &reply, &error);
94 if (!res) {
95 fprintf (stderr, "Error with explain: %s\n", error.message);
96 goto cleanup;
97 }
98
99 /* Do something with the reply */
100 print_res (&reply);
101
102 cleanup:
103 bson_destroy (&reply);
104 bson_destroy (command);
105 return res;
106 }
107
108
109 copydb Command
110 This example requires two instances of mongo to be running.
111
112 Here's how to use the copydb command to copy a database from another
113 instance of MongoDB: copydb.c.INDENT 0.0
114
115 bool
116 copydb (mongoc_client_t *client, const char *other_host_and_port)
117 {
118 mongoc_database_t *admindb;
119 bson_t *command;
120 bson_t reply;
121 bson_error_t error;
122 bool res;
123
124 BSON_ASSERT (other_host_and_port);
125 /* Must do this from the admin db */
126 admindb = mongoc_client_get_database (client, "admin");
127
128 command = BCON_NEW ("copydb",
129 BCON_INT32 (1),
130 "fromdb",
131 BCON_UTF8 ("test"),
132 "todb",
133 BCON_UTF8 ("test2"),
134
135 /* If you want from a different host */
136 "fromhost",
137 BCON_UTF8 (other_host_and_port));
138 res =
139 mongoc_database_command_simple (admindb, command, NULL, &reply, &error);
140 if (!res) {
141 fprintf (stderr, "Error with copydb: %s\n", error.message);
142 goto cleanup;
143 }
144
145 /* Do something with the reply */
146 print_res (&reply);
147
148 cleanup:
149 bson_destroy (&reply);
150 bson_destroy (command);
151 mongoc_database_destroy (admindb);
152
153 return res;
154 }
155
156
157 cloneCollection Command
158 This example requires two instances of mongo to be running.
159
160 Here's an example of the cloneCollection command to clone a collection
161 from another instance of MongoDB: clone-collection.c.INDENT 0.0
162
163 bool
164 clone_collection (mongoc_database_t *database, const char *other_host_and_port)
165 {
166 bson_t *command;
167 bson_t reply;
168 bson_error_t error;
169 bool res;
170
171 BSON_ASSERT (other_host_and_port);
172 command = BCON_NEW ("cloneCollection",
173 BCON_UTF8 ("test.remoteThings"),
174 "from",
175 BCON_UTF8 (other_host_and_port),
176 "query",
177 "{",
178 "x",
179 BCON_INT32 (1),
180 "}");
181 res =
182 mongoc_database_command_simple (database, command, NULL, &reply, &error);
183 if (!res) {
184 fprintf (stderr, "Error with clone: %s\n", error.message);
185 goto cleanup;
186 }
187
188 /* Do something with the reply */
189 print_res (&reply);
190
191 cleanup:
192 bson_destroy (&reply);
193 bson_destroy (command);
194
195 return res;
196 }
197
198
199 Running the Examples
200 common-operations.c.INDENT 0.0
201
202 /*
203 * Copyright 2016 MongoDB, Inc.
204 *
205 * Licensed under the Apache License, Version 2.0 (the "License");
206 * you may not use this file except in compliance with the License.
207 * You may obtain a copy of the License at
208 *
209 * http://www.apache.org/licenses/LICENSE-2.0
210 *
211 * Unless required by applicable law or agreed to in writing, software
212 * distributed under the License is distributed on an "AS IS" BASIS,
213 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
214 * See the License for the specific language governing permissions and
215 * limitations under the License.
216 */
217
218
219 #include <mongoc/mongoc.h>
220 #include <stdio.h>
221
222
223 const char *COLLECTION_NAME = "things";
224
225 #include "../doc-common-insert.c"
226 #include "explain.c"
227 #include "copydb.c"
228 #include "clone-collection.c"
229
230
231 int
232 main (int argc, char *argv[])
233 {
234 mongoc_database_t *database = NULL;
235 mongoc_client_t *client = NULL;
236 mongoc_collection_t *collection = NULL;
237 mongoc_uri_t *uri = NULL;
238 bson_error_t error;
239 char *host_and_port;
240 int res = 0;
241 char *other_host_and_port = NULL;
242
243 if (argc < 2 || argc > 3) {
244 fprintf (stderr,
245 "usage: %s MONGOD-1-CONNECTION-STRING "
246 "[MONGOD-2-HOST-NAME:MONGOD-2-PORT]\n",
247 argv[0]);
248 fprintf (stderr,
249 "MONGOD-1-CONNECTION-STRING can be "
250 "of the following forms:\n");
251 fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
252 fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
253 fprintf (stderr,
254 "mongodb://user:pass@localhost:27017\t"
255 "local machine on port 27017, and authenticate with username "
256 "user and password pass\n");
257 return EXIT_FAILURE;
258 }
259
260 mongoc_init ();
261
262 if (strncmp (argv[1], "mongodb://", 10) == 0) {
263 host_and_port = bson_strdup (argv[1]);
264 } else {
265 host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
266 }
267 other_host_and_port = argc > 2 ? argv[2] : NULL;
268
269 uri = mongoc_uri_new_with_error (host_and_port, &error);
270 if (!uri) {
271 fprintf (stderr,
272 "failed to parse URI: %s\n"
273 "error message: %s\n",
274 host_and_port,
275 error.message);
276 res = EXIT_FAILURE;
277 goto cleanup;
278 }
279
280 client = mongoc_client_new_from_uri (uri);
281 if (!client) {
282 res = EXIT_FAILURE;
283 goto cleanup;
284 }
285
286 mongoc_client_set_error_api (client, 2);
287 database = mongoc_client_get_database (client, "test");
288 collection = mongoc_database_get_collection (database, COLLECTION_NAME);
289
290 printf ("Inserting data\n");
291 if (!insert_data (collection)) {
292 res = EXIT_FAILURE;
293 goto cleanup;
294 }
295
296 printf ("explain\n");
297 if (!explain (collection)) {
298 res = EXIT_FAILURE;
299 goto cleanup;
300 }
301
302 if (other_host_and_port) {
303 printf ("copydb\n");
304 if (!copydb (client, other_host_and_port)) {
305 res = EXIT_FAILURE;
306 goto cleanup;
307 }
308
309 printf ("clone collection\n");
310 if (!clone_collection (database, other_host_and_port)) {
311 res = EXIT_FAILURE;
312 goto cleanup;
313 }
314 }
315
316 cleanup:
317 if (collection) {
318 mongoc_collection_destroy (collection);
319 }
320
321 if (database) {
322 mongoc_database_destroy (database);
323 }
324
325 if (client) {
326 mongoc_client_destroy (client);
327 }
328
329 if (uri) {
330 mongoc_uri_destroy (uri);
331 }
332
333 bson_free (host_and_port);
334 mongoc_cleanup ();
335 return res;
336 }
337
338
339First launch two separate instances of mongod (must be done from separate
340shells):
341
342 $ mongod
343
344 $ mkdir /tmp/db2$ mongod --dbpath /tmp/db2 --port 27018 # second instance
345
346 Now compile and run the example program:
347
348 $ cd examples/common_operations/$ gcc -Wall -o example common-operations.c $(pkg-config --cflags --libs libmongoc-1.0)$ ./example localhost:27017 localhost:27018
349 Inserting data
350 explain
351 {
352 "executionStats" : {
353 "allPlansExecution" : [],
354 "executionStages" : {
355 "advanced" : 19,
356 "direction" : "forward" ,
357 "docsExamined" : 76,
358 "executionTimeMillisEstimate" : 0,
359 "filter" : {
360 "x" : {
361 "$eq" : 1
362 }
363 },
364 "invalidates" : 0,
365 "isEOF" : 1,
366 "nReturned" : 19,
367 "needTime" : 58,
368 "needYield" : 0,
369 "restoreState" : 0,
370 "saveState" : 0,
371 "stage" : "COLLSCAN" ,
372 "works" : 78
373 },
374 "executionSuccess" : true,
375 "executionTimeMillis" : 0,
376 "nReturned" : 19,
377 "totalDocsExamined" : 76,
378 "totalKeysExamined" : 0
379 },
380 "ok" : 1,
381 "queryPlanner" : {
382 "indexFilterSet" : false,
383 "namespace" : "test.things",
384 "parsedQuery" : {
385 "x" : {
386 "$eq" : 1
387 }
388 },
389 "plannerVersion" : 1,
390 "rejectedPlans" : [],
391 "winningPlan" : {
392 "direction" : "forward" ,
393 "filter" : {
394 "x" : {
395 "$eq" : 1
396 }
397 },
398 "stage" : "COLLSCAN"
399 }
400 },
401 "serverInfo" : {
402 "gitVersion" : "05552b562c7a0b3143a729aaa0838e558dc49b25" ,
403 "host" : "MacBook-Pro-57.local",
404 "port" : 27017,
405 "version" : "3.2.6"
406 }
407 }
408 copydb
409 { "ok" : 1 }
410 clone collection
411 { "ok" : 1 }
412
414 The following guide contains information specific to certain types of
415 MongoDB configurations.
416
417 For an example of connecting to a simple standalone server, see the
418 Tutorial. To establish a connection with authentication options
419 enabled, see the Authentication page.
420
421 Connecting to a Replica Set
422 Connecting to a replica set is much like connecting to a standalone
423 MongoDB server. Simply specify the replica set name using the ?repli‐
424 caSet=myreplset URI option.
425
426 #include <bson/bson.h>
427 #include <mongoc/mongoc.h>
428
429 int
430 main (int argc, char *argv[])
431 {
432 mongoc_client_t *client;
433
434 mongoc_init ();
435
436 /* Create our MongoDB Client */
437 client = mongoc_client_new (
438 "mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset");
439
440 /* Do some work */
441 /* TODO */
442
443 /* Clean up */
444 mongoc_client_destroy (client);
445 mongoc_cleanup ();
446
447 return 0;
448 }
449
450 TIP:
451 Multiple hostnames can be specified in the MongoDB connection string
452 URI, with a comma separating hosts in the seed list.
453
454 It is recommended to use a seed list of members of the replica set
455 to allow the driver to connect to any node.
456
457 Connecting to a Sharded Cluster
458 To connect to a sharded cluster, specify the mongos nodes the client
459 should connect to. The C Driver will automatically detect that it has
460 connected to a mongos sharding server.
461
462 If more than one hostname is specified, a seed list will be created to
463 attempt failover between the mongos instances.
464
465 WARNING:
466 Specifying the replicaSet parameter when connecting to a mongos
467 sharding server is invalid.
468
469 #include <bson/bson.h>
470 #include <mongoc/mongoc.h>
471
472 int
473 main (int argc, char *argv[])
474 {
475 mongoc_client_t *client;
476
477 mongoc_init ();
478
479 /* Create our MongoDB Client */
480 client = mongoc_client_new ("mongodb://myshard01:27017/");
481
482 /* Do something with client ... */
483
484 /* Free the client */
485 mongoc_client_destroy (client);
486
487 mongoc_cleanup ();
488
489 return 0;
490 }
491
492 Connecting to an IPv6 Address
493 The MongoDB C Driver will automatically resolve IPv6 addresses from
494 host names. However, to specify an IPv6 address directly, wrap the
495 address in [].
496
497 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://[::1]:27017");
498
499 Connecting with IPv4 and IPv6
500 If connecting to a hostname that has both IPv4 and IPv6 DNS records,
501 the behavior follows RFC-6555. A connection to the IPv6 address is
502 attempted first. If IPv6 fails, then a connection is attempted to the
503 IPv4 address. If the connection attempt to IPv6 does not complete
504 within 250ms, then IPv4 is tried in parallel. Whichever succeeds con‐
505 nection first cancels the other. The successful DNS result is cached
506 for 10 minutes.
507
508 As a consequence, attempts to connect to a mongod only listening on
509 IPv4 may be delayed if there are both A (IPv4) and AAAA (IPv6) DNS
510 records associated with the host.
511
512 To avoid a delay, configure hostnames to match the MongoDB configura‐
513 tion. That is, only create an A record if the mongod is only listening
514 on IPv4.
515
516 Connecting to a UNIX Domain Socket
517 On UNIX-like systems, the C Driver can connect directly to a MongoDB
518 server using a UNIX domain socket. Pass the URL-encoded path to the
519 socket, which must be suffixed with .sock. For example, to connect to a
520 domain socket at /tmp/mongodb-27017.sock:
521
522 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://%2Ftmp%2Fmongodb-27017.sock");
523
524 Include username and password like so:
525
526 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://user:pass@%2Ftmp%2Fmongodb-27017.sock");
527
528 Connecting to a server over SSL
529 These are instructions for configuring TLS/SSL connections.
530
531 To run a server locally (on port 27017, for example):
532
533 $ mongod --port 27017 --sslMode requireSSL --sslPEMKeyFile server.pem --sslCAFile ca.pem
534
535 Add /?ssl=true to the end of a client URI.
536
537 mongoc_client_t *client = NULL;
538 client = mongoc_client_new ("mongodb://localhost:27017/?ssl=true");
539
540 MongoDB requires client certificates by default, unless the --sslAllow‐
541 ConnectionsWithoutCertificates is provided. The C Driver can be config‐
542 ured to present a client certificate using a mongoc_ssl_opt_t:
543
544 const mongoc_ssl_opt_t *ssl_default = mongoc_ssl_opt_get_default ();
545 mongoc_ssl_opt_t ssl_opts = { 0 };
546
547 /* optionally copy in a custom trust directory or file; otherwise the default is used. */
548 memcpy (&ssl_opts, ssl_default, sizeof ssl_opts);
549 ssl_opts.pem_file = "client.pem"
550
551 mongoc_client_set_ssl_opts (client, &ssl_opts);
552
553 The client certificate provided by pem_file must be issued by one of
554 the server trusted Certificate Authorities listed in --sslCAFile, or
555 issued by a CA in the native certificate store on the server when omit‐
556 ted.
557
558 To verify the server certificate against a specific CA, provide a PEM
559 armored file with a CA certificate, or concatenated list of CA certifi‐
560 cates using the ca_file option, or c_rehash directory structure of CAs,
561 pointed to using the ca_dir option. When no ca_file or ca_dir is pro‐
562 vided, the driver will use CAs provided by the native platform certifi‐
563 cate store.
564
565 See mongoc_ssl_opt_t for more information on the various SSL related
566 options.
567
568 Compressing data to and from MongoDB
569 MongoDB 3.4 added Snappy compression support, and zlib compression in
570 3.6. To enable compression support the client must be configured with
571 which compressors to use:
572
573 mongoc_client_t *client = NULL;
574 client = mongoc_client_new ("mongodb://localhost:27017/?compressors=snappy,zlib");
575
576 The compressors option specifies the priority order of compressors the
577 client wants to use. Messages are compressed if the client and server
578 share any compressors in common.
579
580 Note that the compressor used by the server might not be the same com‐
581 pressor as the client used. For example, if the client uses the con‐
582 nection string compressors=zlib,snappy the client will use zlib com‐
583 pression to send data (if possible), but the server might still reply
584 using snappy, depending on how the server was configured.
585
586 The driver must be built with zlib and/or snappy support to enable com‐
587 pression support, any unknown (or not compiled in) compressor value
588 will be ignored.
589
590 Additional Connection Options
591 The full list of connection options can be found in the mongoc_uri_t
592 docs.
593
594 Certain socket/connection related options are not configurable:
595
596
597
598
599 ┌──────────────┬─────────────────────┬─────────────────────┐
600 │Option │ Description │ Value │
601 ├──────────────┼─────────────────────┼─────────────────────┤
602 │SO_KEEPALIVE │ TCP Keep Alive │ Enabled │
603 ├──────────────┼─────────────────────┼─────────────────────┤
604 │TCP_KEEPIDLE │ How long a connec‐ │ 300 seconds │
605 │ │ tion needs to │ │
606 │ │ remain idle before │ │
607 │ │ TCP starts sending │ │
608 │ │ keepalive probes │ │
609 ├──────────────┼─────────────────────┼─────────────────────┤
610 │TCP_KEEPINTVL │ The time in seconds │ 10 seconds │
611 │ │ between TCP probes │ │
612 ├──────────────┼─────────────────────┼─────────────────────┤
613 │TCP_KEEPCNT │ How many probes to │ 9 probes │
614 │ │ send, without │ │
615 │ │ acknowledgement, │ │
616 │ │ before dropping the │ │
617 │ │ connection │ │
618 ├──────────────┼─────────────────────┼─────────────────────┤
619 │TCP_NODELAY │ Send packets as │ Enabled (no buffer‐ │
620 │ │ soon as possible or │ ing) │
621 │ │ buffer small pack‐ │ │
622 │ │ ets (Nagle algo‐ │ │
623 │ │ rithm) │ │
624 └──────────────┴─────────────────────┴─────────────────────┘
625
627 The MongoDB C driver has two connection modes: single-threaded and
628 pooled. Single-threaded mode is optimized for embedding the driver
629 within languages like PHP. Multi-threaded programs should use pooled
630 mode: this mode minimizes the total connection count, and in pooled
631 mode a background thread monitors the MongoDB server topology, so the
632 program need not block to scan it.
633
634 Single Mode
635 In single mode, your program creates a mongoc_client_t directly:
636
637 mongoc_client_t *client = mongoc_client_new (
638 "mongodb://hostA,hostB/?replicaSet=my_rs");
639
640 The client connects on demand when your program first uses it for a
641 MongoDB operation. Using a non-blocking socket per server, it begins a
642 check on each server concurrently, and uses the asynchronous poll or
643 select function to receive events from the sockets, until all have
644 responded or timed out. Put another way, in single-threaded mode the C
645 Driver fans out to begin all checks concurrently, then fans in once all
646 checks have completed or timed out. Once the scan completes, the client
647 executes your program's operation and returns.
648
649 In single mode, the client re-scans the server topology roughly once
650 per minute. If more than a minute has elapsed since the previous scan,
651 the next operation on the client will block while the client completes
652 its scan. This interval is configurable with heartbeatFrequencyMS in
653 the connection string. (See mongoc_uri_t.)
654
655 A single client opens one connection per server in your topology: these
656 connections are used both for scanning the topology and performing nor‐
657 mal operations.
658
659 Pooled Mode
660 To activate pooled mode, create a mongoc_client_pool_t:
661
662 mongoc_uri_t *uri = mongoc_uri_new (
663 "mongodb://hostA,hostB/?replicaSet=my_rs");
664
665 mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
666
667 When your program first calls mongoc_client_pool_pop, the pool launches
668 a background thread for monitoring. The thread fans out and connects to
669 all servers in the connection string, using non-blocking sockets and a
670 simple event loop. As it receives ismaster responses from the servers,
671 it updates its view of the server topology. Each time the thread dis‐
672 covers a new server it begins connecting to it, and adds the new socket
673 to the list of non-blocking sockets in the event loop.
674
675 Each thread that executes MongoDB operations must check out a client
676 from the pool:
677
678 mongoc_client_t *client = mongoc_client_pool_pop (pool);
679
680 /* use the client for operations ... */
681
682 mongoc_client_pool_push (pool, client);
683
684 The mongoc_client_t object is not thread-safe, only the mon‐
685 goc_client_pool_t is.
686
687 When the driver is in pooled mode, your program's operations are
688 unblocked as soon as monitoring discovers a usable server. For example,
689 if a thread in your program is waiting to execute an "insert" on the
690 primary, it is unblocked as soon as the primary is discovered, rather
691 than waiting for all secondaries to be checked as well.
692
693 The pool opens one connection per server for monitoring, and each
694 client opens its own connection to each server it uses for application
695 operations. The background thread re-scans the server topology roughly
696 every 10 seconds. This interval is configurable with heartbeatFrequen‐
697 cyMS in the connection string. (See mongoc_uri_t.)
698
699 See connection_pool_options to configure pool size and behavior, and
700 see mongoc_client_pool_t for an extended example of a multi-threaded
701 program that uses the driver in pooled mode.
702
704 Handling Cursor Failures
705 Cursors exist on a MongoDB server. However, the mongoc_cursor_t struc‐
706 ture gives the local process a handle to the cursor. It is possible for
707 errors to occur on the server while iterating a cursor on the client.
708 Even a network partition may occur. This means that applications should
709 be robust in handling cursor failures.
710
711 While iterating cursors, you should check to see if an error has
712 occurred. See the following example for how to robustly check for
713 errors.
714
715 static void
716 print_all_documents (mongoc_collection_t *collection)
717 {
718 mongoc_cursor_t *cursor;
719 const bson_t *doc;
720 bson_error_t error;
721 bson_t query = BSON_INITIALIZER;
722 char *str;
723
724 cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);
725
726 while (mongoc_cursor_next (cursor, &doc)) {
727 str = bson_as_canonical_extended_json (doc, NULL);
728 printf ("%s\n", str);
729 bson_free (str);
730 }
731
732 if (mongoc_cursor_error (cursor, &error)) {
733 fprintf (stderr, "Failed to iterate all documents: %s\n", error.message);
734 }
735
736 mongoc_cursor_destroy (cursor);
737 }
738
739 Destroying Server-Side Cursors
740 The MongoDB C driver will automatically destroy a server-side cursor
741 when mongoc_cursor_destroy() is called. Failure to call this function
742 when done with a cursor will leak memory client side as well as consume
743 extra memory server side. If the cursor was configured to never time‐
744 out, it will become a memory leak on the server.
745
746 Tailable Cursors
747 Tailable cursors are cursors that remain open even after they've
748 returned a final result. This way, if more documents are added to a
749 collection (i.e., to the cursor's result set), then you can continue to
750 call mongoc_cursor_next() to retrieve those additional results.
751
752 Here's a complete test case that demonstrates the use of tailable cur‐
753 sors.
754
755 NOTE:
756 Tailable cursors are for capped collections only.
757
758 An example to tail the oplog from a replica set. mongoc-tail.c.INDENT
759 0.0
760
761 #include <bson/bson.h>
762 #include <mongoc/mongoc.h>
763 #include <stdio.h>
764 #include <stdlib.h>
765
766 #ifdef _WIN32
767 #define sleep(_n) Sleep ((_n) *1000)
768 #endif
769
770
771 static void
772 print_bson (const bson_t *b)
773 {
774 char *str;
775
776 str = bson_as_canonical_extended_json (b, NULL);
777 fprintf (stdout, "%s\n", str);
778 bson_free (str);
779 }
780
781
782 static mongoc_cursor_t *
783 query_collection (mongoc_collection_t *collection, uint32_t last_time)
784 {
785 mongoc_cursor_t *cursor;
786 bson_t query;
787 bson_t gt;
788 bson_t opts;
789
790 BSON_ASSERT (collection);
791
792 bson_init (&query);
793 BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", >);
794 BSON_APPEND_TIMESTAMP (>, "$gt", last_time, 0);
795 bson_append_document_end (&query, >);
796
797 bson_init (&opts);
798 BSON_APPEND_BOOL (&opts, "tailable", true);
799 BSON_APPEND_BOOL (&opts, "awaitData", true);
800
801 cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL);
802
803 bson_destroy (&query);
804 bson_destroy (&opts);
805
806 return cursor;
807 }
808
809
810 static void
811 tail_collection (mongoc_collection_t *collection)
812 {
813 mongoc_cursor_t *cursor;
814 uint32_t last_time;
815 const bson_t *doc;
816 bson_error_t error;
817 bson_iter_t iter;
818
819 BSON_ASSERT (collection);
820
821 last_time = (uint32_t) time (NULL);
822
823 while (true) {
824 cursor = query_collection (collection, last_time);
825 while (!mongoc_cursor_error (cursor, &error) &&
826 mongoc_cursor_more (cursor)) {
827 if (mongoc_cursor_next (cursor, &doc)) {
828 if (bson_iter_init_find (&iter, doc, "ts") &&
829 BSON_ITER_HOLDS_TIMESTAMP (&iter)) {
830 bson_iter_timestamp (&iter, &last_time, NULL);
831 }
832 print_bson (doc);
833 }
834 }
835 if (mongoc_cursor_error (cursor, &error)) {
836 if (error.domain == MONGOC_ERROR_SERVER) {
837 fprintf (stderr, "%s\n", error.message);
838 exit (1);
839 }
840 }
841
842 mongoc_cursor_destroy (cursor);
843 sleep (1);
844 }
845 }
846
847
848 int
849 main (int argc, char *argv[])
850 {
851 mongoc_collection_t *collection;
852 mongoc_client_t *client;
853 mongoc_uri_t *uri;
854 bson_error_t error;
855
856 if (argc != 2) {
857 fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]);
858 return EXIT_FAILURE;
859 }
860
861 mongoc_init ();
862
863 uri = mongoc_uri_new_with_error (argv[1], &error);
864 if (!uri) {
865 fprintf (stderr,
866 "failed to parse URI: %s\n"
867 "error message: %s\n",
868 argv[1],
869 error.message);
870 return EXIT_FAILURE;
871 }
872
873 client = mongoc_client_new_from_uri (uri);
874 if (!client) {
875 return EXIT_FAILURE;
876 }
877
878 mongoc_client_set_error_api (client, 2);
879
880 collection = mongoc_client_get_collection (client, "local", "oplog.rs");
881
882 tail_collection (collection);
883
884 mongoc_collection_destroy (collection);
885 mongoc_uri_destroy (uri);
886 mongoc_client_destroy (client);
887
888 return EXIT_SUCCESS;
889 }
890
891
892Let's compile and run this example against a replica set to see updates as
893they are made.
894
895 $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0)
896 $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet
897 {
898 "h" : -8458503739429355503,
899 "ns" : "test.test",
900 "o" : {
901 "_id" : {
902 "$oid" : "5372ab0a25164be923d10d50"
903 }
904 },
905 "op" : "i",
906 "ts" : {
907 "$timestamp" : {
908 "i" : 1,
909 "t" : 1400023818
910 }
911 },
912 "v" : 2
913 }
914
915 The line of output is a sample from performing db.test.insert({}) from
916 the mongo shell on the replica set.
917
918 See also mongoc_cursor_set_max_await_time_ms.
919
921 This tutorial explains how to take advantage of MongoDB C driver bulk
922 write operation features. Executing write operations in batches reduces
923 the number of network round trips, increasing write throughput.
924
925 Bulk Insert
926 First we need to fetch a bulk operation handle from the mongoc_collec‐
927 tion_t.
928
929 mongoc_bulk_operation_t *bulk =
930 mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
931
932 We can now start inserting documents to the bulk operation. These will
933 be buffered until we execute the operation.
934
935 The bulk operation will coalesce insertions as a single batch for each
936 consecutive call to mongoc_bulk_operation_insert(). This creates a
937 pipelined effect when possible.
938
939 To execute the bulk operation and receive the result we call mon‐
940 goc_bulk_operation_execute(). bulk1.c.INDENT 0.0
941
942 #include <assert.h>
943 #include <bson/bcon.h>
944 #include <mongoc/mongoc.h>
945 #include <stdio.h>
946
947 static void
948 bulk1 (mongoc_collection_t *collection)
949 {
950 mongoc_bulk_operation_t *bulk;
951 bson_error_t error;
952 bson_t *doc;
953 bson_t reply;
954 char *str;
955 bool ret;
956 int i;
957
958 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
959
960 for (i = 0; i < 10000; i++) {
961 doc = BCON_NEW ("i", BCON_INT32 (i));
962 mongoc_bulk_operation_insert (bulk, doc);
963 bson_destroy (doc);
964 }
965
966 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
967
968 str = bson_as_canonical_extended_json (&reply, NULL);
969 printf ("%s\n", str);
970 bson_free (str);
971
972 if (!ret) {
973 fprintf (stderr, "Error: %s\n", error.message);
974 }
975
976 bson_destroy (&reply);
977 mongoc_bulk_operation_destroy (bulk);
978 }
979
980 int
981 main (int argc, char *argv[])
982 {
983 mongoc_client_t *client;
984 mongoc_collection_t *collection;
985 const char *uri_string = "mongodb://localhost/?appname=bulk1-example";
986 mongoc_uri_t *uri;
987 bson_error_t error;
988
989 mongoc_init ();
990
991 uri = mongoc_uri_new_with_error (uri_string, &error);
992 if (!uri) {
993 fprintf (stderr,
994 "failed to parse URI: %s\n"
995 "error message: %s\n",
996 uri_string,
997 error.message);
998 return EXIT_FAILURE;
999 }
1000
1001 client = mongoc_client_new_from_uri (uri);
1002 if (!client) {
1003 return EXIT_FAILURE;
1004 }
1005
1006 mongoc_client_set_error_api (client, 2);
1007 collection = mongoc_client_get_collection (client, "test", "test");
1008
1009 bulk1 (collection);
1010
1011 mongoc_uri_destroy (uri);
1012 mongoc_collection_destroy (collection);
1013 mongoc_client_destroy (client);
1014
1015 mongoc_cleanup ();
1016
1017 return EXIT_SUCCESS;
1018 }
1019
1020
1021Example reply document:
1022
1023 {"nInserted" : 10000,
1024 "nMatched" : 0,
1025 "nModified" : 0,
1026 "nRemoved" : 0,
1027 "nUpserted" : 0,
1028 "writeErrors" : []
1029 "writeConcernErrors" : [] }
1030
1031 Mixed Bulk Write Operations
1032 MongoDB C driver also supports executing mixed bulk write operations. A
1033 batch of insert, update, and remove operations can be executed together
1034 using the bulk write operations API.
1035
1036 Ordered Bulk Write Operations
1037 Ordered bulk write operations are batched and sent to the server in the
1038 order provided for serial execution. The reply document describes the
1039 type and count of operations performed. bulk2.c.INDENT 0.0
1040
1041 #include <assert.h>
1042 #include <bson/bcon.h>
1043 #include <mongoc/mongoc.h>
1044 #include <stdio.h>
1045
1046 static void
1047 bulk2 (mongoc_collection_t *collection)
1048 {
1049 mongoc_bulk_operation_t *bulk;
1050 bson_error_t error;
1051 bson_t *query;
1052 bson_t *doc;
1053 bson_t *opts;
1054 bson_t reply;
1055 char *str;
1056 bool ret;
1057 int i;
1058
1059 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1060
1061 /* Remove everything */
1062 query = bson_new ();
1063 mongoc_bulk_operation_remove (bulk, query);
1064 bson_destroy (query);
1065
1066 /* Add a few documents */
1067 for (i = 1; i < 4; i++) {
1068 doc = BCON_NEW ("_id", BCON_INT32 (i));
1069 mongoc_bulk_operation_insert (bulk, doc);
1070 bson_destroy (doc);
1071 }
1072
1073 /* {_id: 1} => {$set: {foo: "bar"}} */
1074 query = BCON_NEW ("_id", BCON_INT32 (1));
1075 doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}");
1076 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, NULL, &error);
1077 bson_destroy (query);
1078 bson_destroy (doc);
1079
1080 /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */
1081 opts = BCON_NEW ("upsert", BCON_BOOL (true));
1082 query = BCON_NEW ("_id", BCON_INT32 (4));
1083 doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}");
1084 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, opts, &error);
1085 bson_destroy (query);
1086 bson_destroy (doc);
1087 bson_destroy (opts);
1088
1089 /* replace {j:1} with {j:2} */
1090 query = BCON_NEW ("j", BCON_INT32 (1));
1091 doc = BCON_NEW ("j", BCON_INT32 (2));
1092 mongoc_bulk_operation_replace_one_with_opts (bulk, query, doc, NULL, &error);
1093 bson_destroy (query);
1094 bson_destroy (doc);
1095
1096 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1097
1098 str = bson_as_canonical_extended_json (&reply, NULL);
1099 printf ("%s\n", str);
1100 bson_free (str);
1101
1102 if (!ret) {
1103 printf ("Error: %s\n", error.message);
1104 }
1105
1106 bson_destroy (&reply);
1107 mongoc_bulk_operation_destroy (bulk);
1108 }
1109
1110 int
1111 main (int argc, char *argv[])
1112 {
1113 mongoc_client_t *client;
1114 mongoc_collection_t *collection;
1115 const char *uri_string = "mongodb://localhost/?appname=bulk2-example";
1116 mongoc_uri_t *uri;
1117 bson_error_t error;
1118
1119 mongoc_init ();
1120
1121 uri = mongoc_uri_new_with_error (uri_string, &error);
1122 if (!uri) {
1123 fprintf (stderr,
1124 "failed to parse URI: %s\n"
1125 "error message: %s\n",
1126 uri_string,
1127 error.message);
1128 return EXIT_FAILURE;
1129 }
1130
1131 client = mongoc_client_new_from_uri (uri);
1132 if (!client) {
1133 return EXIT_FAILURE;
1134 }
1135
1136 mongoc_client_set_error_api (client, 2);
1137 collection = mongoc_client_get_collection (client, "test", "test");
1138
1139 bulk2 (collection);
1140
1141 mongoc_uri_destroy (uri);
1142 mongoc_collection_destroy (collection);
1143 mongoc_client_destroy (client);
1144
1145 mongoc_cleanup ();
1146
1147 return EXIT_SUCCESS;
1148 }
1149
1150
1151Example reply document:
1152
1153 { "nInserted" : 3,
1154 "nMatched" : 2,
1155 "nModified" : 2,
1156 "nRemoved" : 10000,
1157 "nUpserted" : 1,
1158 "upserted" : [{"index" : 5, "_id" : 4}],
1159 "writeErrors" : []
1160 "writeConcernErrors" : [] }
1161
1162 The index field in the upserted array is the 0-based index of the
1163 upsert operation; in this example, the sixth operation of the overall
1164 bulk operation was an upsert, so its index is 5.
1165
1166 Unordered Bulk Write Operations
1167 Unordered bulk write operations are batched and sent to the server in
1168 arbitrary order where they may be executed in parallel. Any errors that
1169 occur are reported after all operations are attempted.
1170
1171 In the next example the first and third operations fail due to the
1172 unique constraint on _id. Since we are doing unordered execution the
1173 second and fourth operations succeed. bulk3.c.INDENT 0.0
1174
1175 #include <assert.h>
1176 #include <bson/bcon.h>
1177 #include <mongoc/mongoc.h>
1178 #include <stdio.h>
1179
1180 static void
1181 bulk3 (mongoc_collection_t *collection)
1182 {
1183 bson_t opts = BSON_INITIALIZER;
1184 mongoc_bulk_operation_t *bulk;
1185 bson_error_t error;
1186 bson_t *query;
1187 bson_t *doc;
1188 bson_t reply;
1189 char *str;
1190 bool ret;
1191
1192 /* false indicates unordered */
1193 BSON_APPEND_BOOL (&opts, "ordered", false);
1194 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1195 bson_destroy (&opts);
1196
1197 /* Add a document */
1198 doc = BCON_NEW ("_id", BCON_INT32 (1));
1199 mongoc_bulk_operation_insert (bulk, doc);
1200 bson_destroy (doc);
1201
1202 /* remove {_id: 2} */
1203 query = BCON_NEW ("_id", BCON_INT32 (2));
1204 mongoc_bulk_operation_remove_one (bulk, query);
1205 bson_destroy (query);
1206
1207 /* insert {_id: 3} */
1208 doc = BCON_NEW ("_id", BCON_INT32 (3));
1209 mongoc_bulk_operation_insert (bulk, doc);
1210 bson_destroy (doc);
1211
1212 /* replace {_id:4} {'i': 1} */
1213 query = BCON_NEW ("_id", BCON_INT32 (4));
1214 doc = BCON_NEW ("i", BCON_INT32 (1));
1215 mongoc_bulk_operation_replace_one (bulk, query, doc, false);
1216 bson_destroy (query);
1217 bson_destroy (doc);
1218
1219 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1220
1221 str = bson_as_canonical_extended_json (&reply, NULL);
1222 printf ("%s\n", str);
1223 bson_free (str);
1224
1225 if (!ret) {
1226 printf ("Error: %s\n", error.message);
1227 }
1228
1229 bson_destroy (&reply);
1230 mongoc_bulk_operation_destroy (bulk);
1231 bson_destroy (&opts);
1232 }
1233
1234 int
1235 main (int argc, char *argv[])
1236 {
1237 mongoc_client_t *client;
1238 mongoc_collection_t *collection;
1239 const char *uri_string = "mongodb://localhost/?appname=bulk3-example";
1240 mongoc_uri_t *uri;
1241 bson_error_t error;
1242
1243 mongoc_init ();
1244
1245 uri = mongoc_uri_new_with_error (uri_string, &error);
1246 if (!uri) {
1247 fprintf (stderr,
1248 "failed to parse URI: %s\n"
1249 "error message: %s\n",
1250 uri_string,
1251 error.message);
1252 return EXIT_FAILURE;
1253 }
1254
1255 client = mongoc_client_new_from_uri (uri);
1256 if (!client) {
1257 return EXIT_FAILURE;
1258 }
1259
1260 mongoc_client_set_error_api (client, 2);
1261 collection = mongoc_client_get_collection (client, "test", "test");
1262
1263 bulk3 (collection);
1264
1265 mongoc_uri_destroy (uri);
1266 mongoc_collection_destroy (collection);
1267 mongoc_client_destroy (client);
1268
1269 mongoc_cleanup ();
1270
1271 return EXIT_SUCCESS;
1272 }
1273
1274
1275Example reply document:
1276
1277 { "nInserted" : 0,
1278 "nMatched" : 1,
1279 "nModified" : 1,
1280 "nRemoved" : 1,
1281 "nUpserted" : 0,
1282 "writeErrors" : [
1283 { "index" : 0,
1284 "code" : 11000,
1285 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" },
1286 { "index" : 2,
1287 "code" : 11000,
1288 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ],
1289 "writeConcernErrors" : [] }
1290
1291 Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }
1292
1293 The bson_error_t domain is MONGOC_ERROR_COMMAND and its code is 11000.
1294
1295 Bulk Operation Bypassing Document Validation
1296 This feature is only available when using MongoDB 3.2 and later.
1297
1298 By default bulk operations are validated against the schema, if any is
1299 defined. In certain cases however it may be necessary to bypass the
1300 document validation. bulk5.c.INDENT 0.0
1301
1302 #include <assert.h>
1303 #include <bson/bcon.h>
1304 #include <mongoc/mongoc.h>
1305 #include <stdio.h>
1306
1307 static void
1308 bulk5_fail (mongoc_collection_t *collection)
1309 {
1310 mongoc_bulk_operation_t *bulk;
1311 bson_error_t error;
1312 bson_t *doc;
1313 bson_t reply;
1314 char *str;
1315 bool ret;
1316
1317 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1318
1319 /* Two inserts */
1320 doc = BCON_NEW ("_id", BCON_INT32 (31));
1321 mongoc_bulk_operation_insert (bulk, doc);
1322 bson_destroy (doc);
1323
1324 doc = BCON_NEW ("_id", BCON_INT32 (32));
1325 mongoc_bulk_operation_insert (bulk, doc);
1326 bson_destroy (doc);
1327
1328 /* The above documents do not comply to the schema validation rules
1329 * we created previously, so this will result in an error */
1330 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1331
1332 str = bson_as_canonical_extended_json (&reply, NULL);
1333 printf ("%s\n", str);
1334 bson_free (str);
1335
1336 if (!ret) {
1337 printf ("Error: %s\n", error.message);
1338 }
1339
1340 bson_destroy (&reply);
1341 mongoc_bulk_operation_destroy (bulk);
1342 }
1343
1344 static void
1345 bulk5_success (mongoc_collection_t *collection)
1346 {
1347 mongoc_bulk_operation_t *bulk;
1348 bson_error_t error;
1349 bson_t *doc;
1350 bson_t reply;
1351 char *str;
1352 bool ret;
1353
1354 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1355
1356 /* Allow this document to bypass document validation.
1357 * NOTE: When authentication is enabled, the authenticated user must have
1358 * either the "dbadmin" or "restore" roles to bypass document validation */
1359 mongoc_bulk_operation_set_bypass_document_validation (bulk, true);
1360
1361 /* Two inserts */
1362 doc = BCON_NEW ("_id", BCON_INT32 (31));
1363 mongoc_bulk_operation_insert (bulk, doc);
1364 bson_destroy (doc);
1365
1366 doc = BCON_NEW ("_id", BCON_INT32 (32));
1367 mongoc_bulk_operation_insert (bulk, doc);
1368 bson_destroy (doc);
1369
1370 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1371
1372 str = bson_as_canonical_extended_json (&reply, NULL);
1373 printf ("%s\n", str);
1374 bson_free (str);
1375
1376 if (!ret) {
1377 printf ("Error: %s\n", error.message);
1378 }
1379
1380 bson_destroy (&reply);
1381 mongoc_bulk_operation_destroy (bulk);
1382 }
1383
1384 int
1385 main (int argc, char *argv[])
1386 {
1387 bson_t *options;
1388 bson_error_t error;
1389 mongoc_client_t *client;
1390 mongoc_collection_t *collection;
1391 mongoc_database_t *database;
1392 const char *uri_string = "mongodb://localhost/?appname=bulk5-example";
1393 mongoc_uri_t *uri;
1394
1395 mongoc_init ();
1396
1397 uri = mongoc_uri_new_with_error (uri_string, &error);
1398 if (!uri) {
1399 fprintf (stderr,
1400 "failed to parse URI: %s\n"
1401 "error message: %s\n",
1402 uri_string,
1403 error.message);
1404 return EXIT_FAILURE;
1405 }
1406
1407 client = mongoc_client_new_from_uri (uri);
1408 if (!client) {
1409 return EXIT_FAILURE;
1410 }
1411
1412 mongoc_client_set_error_api (client, 2);
1413 database = mongoc_client_get_database (client, "testasdf");
1414
1415 /* Create schema validator */
1416 options = BCON_NEW (
1417 "validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}");
1418 collection =
1419 mongoc_database_create_collection (database, "collname", options, &error);
1420
1421 if (collection) {
1422 bulk5_fail (collection);
1423 bulk5_success (collection);
1424 mongoc_collection_destroy (collection);
1425 } else {
1426 fprintf (stderr, "Couldn't create collection: '%s'\n", error.message);
1427 }
1428
1429 bson_free (options);
1430 mongoc_uri_destroy (uri);
1431 mongoc_database_destroy (database);
1432 mongoc_client_destroy (client);
1433
1434 mongoc_cleanup ();
1435
1436 return EXIT_SUCCESS;
1437 }
1438
1439
1440Running the above example will result in:
1441
1442 { "nInserted" : 0,
1443 "nMatched" : 0,
1444 "nModified" : 0,
1445 "nRemoved" : 0,
1446 "nUpserted" : 0,
1447 "writeErrors" : [
1448 { "index" : 0,
1449 "code" : 121,
1450 "errmsg" : "Document failed validation" } ] }
1451
1452 Error: Document failed validation
1453
1454 { "nInserted" : 2,
1455 "nMatched" : 0,
1456 "nModified" : 0,
1457 "nRemoved" : 0,
1458 "nUpserted" : 0,
1459 "writeErrors" : [] }
1460
1461 The bson_error_t domain is MONGOC_ERROR_COMMAND.
1462
1463 Bulk Operation Write Concerns
1464 By default bulk operations are executed with the write_concern of the
1465 collection they are executed against. A custom write concern can be
1466 passed to the mongoc_collection_create_bulk_operation_with_opts()
1467 method. Write concern errors (e.g. wtimeout) will be reported after all
1468 operations are attempted, regardless of execution order.
1469 bulk4.c.INDENT 0.0
1470
1471 #include <assert.h>
1472 #include <bson/bcon.h>
1473 #include <mongoc/mongoc.h>
1474 #include <stdio.h>
1475
1476 static void
1477 bulk4 (mongoc_collection_t *collection)
1478 {
1479 bson_t opts = BSON_INITIALIZER;
1480 mongoc_write_concern_t *wc;
1481 mongoc_bulk_operation_t *bulk;
1482 bson_error_t error;
1483 bson_t *doc;
1484 bson_t reply;
1485 char *str;
1486 bool ret;
1487
1488 wc = mongoc_write_concern_new ();
1489 mongoc_write_concern_set_w (wc, 4);
1490 mongoc_write_concern_set_wtimeout (wc, 100); /* milliseconds */
1491 mongoc_write_concern_append (wc, &opts);
1492
1493 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1494
1495 /* Two inserts */
1496 doc = BCON_NEW ("_id", BCON_INT32 (10));
1497 mongoc_bulk_operation_insert (bulk, doc);
1498 bson_destroy (doc);
1499
1500 doc = BCON_NEW ("_id", BCON_INT32 (11));
1501 mongoc_bulk_operation_insert (bulk, doc);
1502 bson_destroy (doc);
1503
1504 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1505
1506 str = bson_as_canonical_extended_json (&reply, NULL);
1507 printf ("%s\n", str);
1508 bson_free (str);
1509
1510 if (!ret) {
1511 printf ("Error: %s\n", error.message);
1512 }
1513
1514 bson_destroy (&reply);
1515 mongoc_bulk_operation_destroy (bulk);
1516 mongoc_write_concern_destroy (wc);
1517 bson_destroy (&opts);
1518 }
1519
1520 int
1521 main (int argc, char *argv[])
1522 {
1523 mongoc_client_t *client;
1524 mongoc_collection_t *collection;
1525 const char *uri_string = "mongodb://localhost/?appname=bulk4-example";
1526 mongoc_uri_t *uri;
1527 bson_error_t error;
1528
1529 mongoc_init ();
1530
1531 uri = mongoc_uri_new_with_error (uri_string, &error);
1532 if (!uri) {
1533 fprintf (stderr,
1534 "failed to parse URI: %s\n"
1535 "error message: %s\n",
1536 uri_string,
1537 error.message);
1538 return EXIT_FAILURE;
1539 }
1540
1541 client = mongoc_client_new_from_uri (uri);
1542 if (!client) {
1543 return EXIT_FAILURE;
1544 }
1545
1546 mongoc_client_set_error_api (client, 2);
1547 collection = mongoc_client_get_collection (client, "test", "test");
1548
1549 bulk4 (collection);
1550
1551 mongoc_uri_destroy (uri);
1552 mongoc_collection_destroy (collection);
1553 mongoc_client_destroy (client);
1554
1555 mongoc_cleanup ();
1556
1557 return EXIT_SUCCESS;
1558 }
1559
1560
1561Example reply document and error message:
1562
1563 { "nInserted" : 2,
1564 "nMatched" : 0,
1565 "nModified" : 0,
1566 "nRemoved" : 0,
1567 "nUpserted" : 0,
1568 "writeErrors" : [],
1569 "writeConcernErrors" : [
1570 { "code" : 64,
1571 "errmsg" : "waiting for replication timed out" }
1572 ] }
1573
1574 Error: waiting for replication timed out
1575
1576 The bson_error_t domain is MONGOC_ERROR_WRITE_CONCERN if there are
1577 write concern errors and no write errors. Write errors indicate failed
1578 operations, so they take precedence over write concern errors, which
1579 mean merely that the write concern is not satisfied yet.
1580
1581 Setting Collation Order
1582 This feature is only available when using MongoDB 3.4 and later.
1583 bulk-collation.c.INDENT 0.0
1584
1585 #include <bson/bcon.h>
1586 #include <mongoc/mongoc.h>
1587 #include <stdio.h>
1588
1589 static void
1590 bulk_collation (mongoc_collection_t *collection)
1591 {
1592 mongoc_bulk_operation_t *bulk;
1593 bson_t *opts;
1594 bson_t *doc;
1595 bson_t *selector;
1596 bson_t *update;
1597 bson_error_t error;
1598 bson_t reply;
1599 char *str;
1600 uint32_t ret;
1601
1602 /* insert {_id: "one"} and {_id: "One"} */
1603 bulk = mongoc_collection_create_bulk_operation_with_opts (
1604 collection, NULL);
1605 doc = BCON_NEW ("_id", BCON_UTF8 ("one"));
1606 mongoc_bulk_operation_insert (bulk, doc);
1607 bson_destroy (doc);
1608
1609 doc = BCON_NEW ("_id", BCON_UTF8 ("One"));
1610 mongoc_bulk_operation_insert (bulk, doc);
1611 bson_destroy (doc);
1612
1613 /* "One" normally sorts before "one"; make "one" come first */
1614 opts = BCON_NEW ("collation",
1615 "{",
1616 "locale",
1617 BCON_UTF8 ("en_US"),
1618 "caseFirst",
1619 BCON_UTF8 ("lower"),
1620 "}");
1621
1622 /* set x=1 on the document with _id "One", which now sorts after "one" */
1623 update = BCON_NEW ("$set", "{", "x", BCON_INT64 (1), "}");
1624 selector = BCON_NEW ("_id", "{", "$gt", BCON_UTF8 ("one"), "}");
1625 mongoc_bulk_operation_update_one_with_opts (
1626 bulk, selector, update, opts, &error);
1627
1628 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1629
1630 str = bson_as_canonical_extended_json (&reply, NULL);
1631 printf ("%s\n", str);
1632 bson_free (str);
1633
1634 if (!ret) {
1635 printf ("Error: %s\n", error.message);
1636 }
1637
1638 bson_destroy (&reply);
1639 bson_destroy (update);
1640 bson_destroy (selector);
1641 bson_destroy (opts);
1642 mongoc_bulk_operation_destroy (bulk);
1643 }
1644
1645 int
1646 main (int argc, char *argv[])
1647 {
1648 mongoc_client_t *client;
1649 mongoc_collection_t *collection;
1650 const char *uri_string = "mongodb://localhost/?appname=bulk-collation";
1651 mongoc_uri_t *uri;
1652 bson_error_t error;
1653
1654 mongoc_init ();
1655
1656 uri = mongoc_uri_new_with_error (uri_string, &error);
1657 if (!uri) {
1658 fprintf (stderr,
1659 "failed to parse URI: %s\n"
1660 "error message: %s\n",
1661 uri_string,
1662 error.message);
1663 return EXIT_FAILURE;
1664 }
1665
1666 client = mongoc_client_new_from_uri (uri);
1667 if (!client) {
1668 return EXIT_FAILURE;
1669 }
1670
1671 mongoc_client_set_error_api (client, 2);
1672 collection = mongoc_client_get_collection (client, "db", "collection");
1673 bulk_collation (collection);
1674
1675 mongoc_uri_destroy (uri);
1676 mongoc_collection_destroy (collection);
1677 mongoc_client_destroy (client);
1678
1679 mongoc_cleanup ();
1680
1681 return EXIT_SUCCESS;
1682 }
1683
1684
1685Running the above example will result in:
1686
1687 { "nInserted" : 2,
1688 "nMatched" : 1,
1689 "nModified" : 1,
1690 "nRemoved" : 0,
1691 "nUpserted" : 0,
1692 "writeErrors" : [ ]
1693 }
1694
1695 Unacknowledged Bulk Writes
1696 Set "w" to zero for an unacknowledged write. The driver sends unac‐
1697 knowledged writes using the legacy opcodes OP_INSERT, OP_UPDATE, and
1698 OP_DELETE. bulk6.c.INDENT 0.0
1699
1700 #include <bson/bcon.h>
1701 #include <mongoc/mongoc.h>
1702 #include <stdio.h>
1703
1704 static void
1705 bulk6 (mongoc_collection_t *collection)
1706 {
1707 bson_t opts = BSON_INITIALIZER;
1708 mongoc_write_concern_t *wc;
1709 mongoc_bulk_operation_t *bulk;
1710 bson_error_t error;
1711 bson_t *doc;
1712 bson_t *selector;
1713 bson_t reply;
1714 char *str;
1715 bool ret;
1716
1717 wc = mongoc_write_concern_new ();
1718 mongoc_write_concern_set_w (wc, 0);
1719 mongoc_write_concern_append (wc, &opts);
1720
1721 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1722
1723 doc = BCON_NEW ("_id", BCON_INT32 (10));
1724 mongoc_bulk_operation_insert (bulk, doc);
1725 bson_destroy (doc);
1726
1727 selector = BCON_NEW ("_id", BCON_INT32 (11));
1728 mongoc_bulk_operation_remove_one (bulk, selector);
1729 bson_destroy (selector);
1730
1731 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1732
1733 str = bson_as_canonical_extended_json (&reply, NULL);
1734 printf ("%s\n", str);
1735 bson_free (str);
1736
1737 if (!ret) {
1738 printf ("Error: %s\n", error.message);
1739 }
1740
1741 bson_destroy (&reply);
1742 mongoc_bulk_operation_destroy (bulk);
1743 mongoc_write_concern_destroy (wc);
1744 bson_destroy (&opts);
1745 }
1746
1747 int
1748 main (int argc, char *argv[])
1749 {
1750 mongoc_client_t *client;
1751 mongoc_collection_t *collection;
1752 const char *uri_string = "mongodb://localhost/?appname=bulk6-example";
1753 mongoc_uri_t *uri;
1754 bson_error_t error;
1755
1756 mongoc_init ();
1757
1758 uri = mongoc_uri_new_with_error (uri_string, &error);
1759 if (!uri) {
1760 fprintf (stderr,
1761 "failed to parse URI: %s\n"
1762 "error message: %s\n",
1763 uri_string,
1764 error.message);
1765 return EXIT_FAILURE;
1766 }
1767
1768 client = mongoc_client_new_from_uri (uri);
1769 if (!client) {
1770 return EXIT_FAILURE;
1771 }
1772
1773 mongoc_client_set_error_api (client, 2);
1774 collection = mongoc_client_get_collection (client, "test", "test");
1775
1776 bulk6 (collection);
1777
1778 mongoc_uri_destroy (uri);
1779 mongoc_collection_destroy (collection);
1780 mongoc_client_destroy (client);
1781
1782 mongoc_cleanup ();
1783
1784 return EXIT_SUCCESS;
1785 }
1786
1787
1788The reply document is empty:
1789
1790 { }
1791
1792 Further Reading
1793 See the Driver Bulk API Spec, which describes bulk write operations for
1794 all MongoDB drivers.
1795
1797 This document provides a number of practical examples that display the
1798 capabilities of the aggregation framework.
1799
1800 The Aggregations using the Zip Codes Data Set examples uses a publicly
1801 available data set of all zipcodes and populations in the United
1802 States. These data are available at: zips.json.
1803
1804 Requirements
1805 Let's check if everything is installed.
1806
1807 Use the following command to load zips.json data set into mongod
1808 instance:
1809
1810 $ mongoimport --drop -d test -c zipcodes zips.json
1811
1812 Let's use the MongoDB shell to verify that everything was imported suc‐
1813 cessfully.
1814
1815 $ mongo test
1816 connecting to: test
1817 > db.zipcodes.count()
1818 29467
1819 > db.zipcodes.findOne()
1820 {
1821 "_id" : "35004",
1822 "city" : "ACMAR",
1823 "loc" : [
1824 -86.51557,
1825 33.584132
1826 ],
1827 "pop" : 6055,
1828 "state" : "AL"
1829 }
1830
1831 Aggregations using the Zip Codes Data Set
1832 Each document in this collection has the following form:
1833
1834 {
1835 "_id" : "35004",
1836 "city" : "Acmar",
1837 "state" : "AL",
1838 "pop" : 6055,
1839 "loc" : [-86.51557, 33.584132]
1840 }
1841
1842 In these documents:
1843
1844 · The _id field holds the zipcode as a string.
1845
1846 · The city field holds the city name.
1847
1848 · The state field holds the two letter state abbreviation.
1849
1850 · The pop field holds the population.
1851
1852 · The loc field holds the location as a [latitude, longitude] array.
1853
1854 States with Populations Over 10 Million
1855 To get all states with a population greater than 10 million, use the
1856 following aggregation pipeline: aggregation1.c.INDENT 0.0
1857
1858 #include <mongoc/mongoc.h>
1859 #include <stdio.h>
1860
1861 static void
1862 print_pipeline (mongoc_collection_t *collection)
1863 {
1864 mongoc_cursor_t *cursor;
1865 bson_error_t error;
1866 const bson_t *doc;
1867 bson_t *pipeline;
1868 char *str;
1869
1870 pipeline = BCON_NEW ("pipeline",
1871 "[",
1872 "{",
1873 "$group",
1874 "{",
1875 "_id",
1876 "$state",
1877 "total_pop",
1878 "{",
1879 "$sum",
1880 "$pop",
1881 "}",
1882 "}",
1883 "}",
1884 "{",
1885 "$match",
1886 "{",
1887 "total_pop",
1888 "{",
1889 "$gte",
1890 BCON_INT32 (10000000),
1891 "}",
1892 "}",
1893 "}",
1894 "]");
1895
1896 cursor = mongoc_collection_aggregate (
1897 collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL);
1898
1899 while (mongoc_cursor_next (cursor, &doc)) {
1900 str = bson_as_canonical_extended_json (doc, NULL);
1901 printf ("%s\n", str);
1902 bson_free (str);
1903 }
1904
1905 if (mongoc_cursor_error (cursor, &error)) {
1906 fprintf (stderr, "Cursor Failure: %s\n", error.message);
1907 }
1908
1909 mongoc_cursor_destroy (cursor);
1910 bson_destroy (pipeline);
1911 }
1912
1913 int
1914 main (int argc, char *argv[])
1915 {
1916 mongoc_client_t *client;
1917 mongoc_collection_t *collection;
1918 const char *uri_string =
1919 "mongodb://localhost:27017/?appname=aggregation-example";
1920 mongoc_uri_t *uri;
1921 bson_error_t error;
1922
1923 mongoc_init ();
1924
1925 uri = mongoc_uri_new_with_error (uri_string, &error);
1926 if (!uri) {
1927 fprintf (stderr,
1928 "failed to parse URI: %s\n"
1929 "error message: %s\n",
1930 uri_string,
1931 error.message);
1932 return EXIT_FAILURE;
1933 }
1934
1935 client = mongoc_client_new_from_uri (uri);
1936 if (!client) {
1937 return EXIT_FAILURE;
1938 }
1939
1940 mongoc_client_set_error_api (client, 2);
1941 collection = mongoc_client_get_collection (client, "test", "zipcodes");
1942
1943 print_pipeline (collection);
1944
1945 mongoc_uri_destroy (uri);
1946 mongoc_collection_destroy (collection);
1947 mongoc_client_destroy (client);
1948
1949 mongoc_cleanup ();
1950
1951 return EXIT_SUCCESS;
1952 }
1953
1954
1955You should see a result like the following:
1956
1957 { "_id" : "PA", "total_pop" : 11881643 }
1958 { "_id" : "OH", "total_pop" : 10847115 }
1959 { "_id" : "NY", "total_pop" : 17990455 }
1960 { "_id" : "FL", "total_pop" : 12937284 }
1961 { "_id" : "TX", "total_pop" : 16986510 }
1962 { "_id" : "IL", "total_pop" : 11430472 }
1963 { "_id" : "CA", "total_pop" : 29760021 }
1964
1965 The above aggregation pipeline is build from two pipeline operators:
1966 $group and $match.
1967
1968 The $group pipeline operator requires _id field where we specify group‐
1969 ing; remaining fields specify how to generate composite value and must
1970 use one of the group aggregation functions: $addToSet, $first, $last,
1971 $max, $min, $avg, $push, $sum. The $match pipeline operator syntax is
1972 the same as the read operation query syntax.
1973
1974 The $group process reads all documents and for each state it creates a
1975 separate document, for example:
1976
1977 { "_id" : "WA", "total_pop" : 4866692 }
1978
1979 The total_pop field uses the $sum aggregation function to sum the val‐
1980 ues of all pop fields in the source documents.
1981
1982 Documents created by $group are piped to the $match pipeline operator.
1983 It returns the documents with the value of total_pop field greater than
1984 or equal to 10 million.
1985
1986 Average City Population by State
1987 To get the first three states with the greatest average population per
1988 city, use the following aggregation:
1989
1990 pipeline = BCON_NEW ("pipeline", "[",
1991 "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}",
1992 "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}",
1993 "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}",
1994 "{", "$limit", BCON_INT32 (3) "}",
1995 "]");
1996
1997 This aggregate pipeline produces:
1998
1999 { "_id" : "DC", "avg_city_pop" : 303450.0 }
2000 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2001 { "_id" : "CA", "avg_city_pop" : 27735.341099720412 }
2002
2003 The above aggregation pipeline is build from three pipeline operators:
2004 $group, $sort and $limit.
2005
2006 The first $group operator creates the following documents:
2007
2008 { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 }
2009
2010 Note, that the $group operator can't use nested documents except the
2011 _id field.
2012
2013 The second $group uses these documents to create the following docu‐
2014 ments:
2015
2016 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2017
2018 These documents are sorted by the avg_city_pop field in descending
2019 order. Finally, the $limit pipeline operator returns the first 3 docu‐
2020 ments from the sorted set.
2021
2023 This document provides some practical, simple, examples to demonstrate
2024 the distinct and mapReduce commands.
2025
2026 Setup
2027 First we'll write some code to insert sample data: doc-com‐
2028 mon-insert.c.INDENT 0.0
2029
2030 /* Don't try to compile this file on its own. It's meant to be #included
2031 by example code */
2032
2033 /* Insert some sample data */
2034 bool
2035 insert_data (mongoc_collection_t *collection)
2036 {
2037 mongoc_bulk_operation_t *bulk;
2038 enum N { ndocs = 4 };
2039 bson_t *docs[ndocs];
2040 bson_error_t error;
2041 int i = 0;
2042 bool ret;
2043
2044 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
2045
2046 docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
2047 docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
2048 docs[2] = BCON_NEW (
2049 "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
2050 docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
2051
2052 for (i = 0; i < ndocs; i++) {
2053 mongoc_bulk_operation_insert (bulk, docs[i]);
2054 bson_destroy (docs[i]);
2055 docs[i] = NULL;
2056 }
2057
2058 ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
2059
2060 if (!ret) {
2061 fprintf (stderr, "Error inserting data: %s\n", error.message);
2062 }
2063
2064 mongoc_bulk_operation_destroy (bulk);
2065 return ret;
2066 }
2067
2068 /* A helper which we'll use a lot later on */
2069 void
2070 print_res (const bson_t *reply)
2071 {
2072 char *str;
2073 BSON_ASSERT (reply);
2074 str = bson_as_canonical_extended_json (reply, NULL);
2075 printf ("%s\n", str);
2076 bson_free (str);
2077 }
2078
2079
2080 distinct command
2081 This is how to use the distinct command to get the distinct values of x
2082 which are greater than 1: distinct.c.INDENT 0.0
2083
2084 bool
2085 distinct (mongoc_database_t *database)
2086 {
2087 bson_t *command;
2088 bson_t reply;
2089 bson_error_t error;
2090 bool res;
2091 bson_iter_t iter;
2092 bson_iter_t array_iter;
2093 double val;
2094
2095 command = BCON_NEW ("distinct",
2096 BCON_UTF8 (COLLECTION_NAME),
2097 "key",
2098 BCON_UTF8 ("x"),
2099 "query",
2100 "{",
2101 "x",
2102 "{",
2103 "$gt",
2104 BCON_DOUBLE (1.0),
2105 "}",
2106 "}");
2107 res =
2108 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2109 if (!res) {
2110 fprintf (stderr, "Error with distinct: %s\n", error.message);
2111 goto cleanup;
2112 }
2113
2114 /* Do something with reply (in this case iterate through the values) */
2115 if (!(bson_iter_init_find (&iter, &reply, "values") &&
2116 BSON_ITER_HOLDS_ARRAY (&iter) &&
2117 bson_iter_recurse (&iter, &array_iter))) {
2118 fprintf (stderr, "Couldn't extract \"values\" field from response\n");
2119 goto cleanup;
2120 }
2121
2122 while (bson_iter_next (&array_iter)) {
2123 if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) {
2124 val = bson_iter_double (&array_iter);
2125 printf ("Next double: %f\n", val);
2126 }
2127 }
2128
2129 cleanup:
2130 /* cleanup */
2131 bson_destroy (command);
2132 bson_destroy (&reply);
2133 return res;
2134 }
2135
2136
2137 mapReduce - basic example
2138 A simple example using the map reduce framework. It simply adds up the
2139 number of occurrences of each "tag".
2140
2141 First define the map and reduce functions: constants.c.INDENT 0.0
2142
2143 const char *const COLLECTION_NAME = "things";
2144
2145 /* Our map function just emits a single (key, 1) pair for each tag
2146 in the array: */
2147 const char *const MAPPER = "function () {"
2148 "this.tags.forEach(function(z) {"
2149 "emit(z, 1);"
2150 "});"
2151 "}";
2152
2153 /* The reduce function sums over all of the emitted values for a
2154 given key: */
2155 const char *const REDUCER = "function (key, values) {"
2156 "var total = 0;"
2157 "for (var i = 0; i < values.length; i++) {"
2158 "total += values[i];"
2159 "}"
2160 "return total;"
2161 "}";
2162 /* Note We can't just return values.length as the reduce function
2163 might be called iteratively on the results of other reduce
2164 steps. */
2165
2166
2167Run the mapReduce command: map-reduce-basic.c.INDENT 0.0
2168
2169 bool
2170 map_reduce_basic (mongoc_database_t *database)
2171 {
2172 bson_t reply;
2173 bson_t *command;
2174 bool res;
2175 bson_error_t error;
2176 mongoc_cursor_t *cursor;
2177 const bson_t *doc;
2178
2179 bool query_done = false;
2180
2181 const char *out_collection_name = "outCollection";
2182 mongoc_collection_t *out_collection;
2183
2184 /* Empty find query */
2185 bson_t find_query = BSON_INITIALIZER;
2186
2187 /* Construct the mapReduce command */
2188
2189 /* Other arguments can also be specified here, like "query" or
2190 "limit" and so on */
2191 command = BCON_NEW ("mapReduce",
2192 BCON_UTF8 (COLLECTION_NAME),
2193 "map",
2194 BCON_CODE (MAPPER),
2195 "reduce",
2196 BCON_CODE (REDUCER),
2197 "out",
2198 BCON_UTF8 (out_collection_name));
2199 res =
2200 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2201
2202 if (!res) {
2203 fprintf (stderr, "MapReduce failed: %s\n", error.message);
2204 goto cleanup;
2205 }
2206
2207 /* Do something with the reply (it doesn't contain the mapReduce results) */
2208 print_res (&reply);
2209
2210 /* Now we'll query outCollection to see what the results are */
2211 out_collection =
2212 mongoc_database_get_collection (database, out_collection_name);
2213 cursor = mongoc_collection_find_with_opts (
2214 out_collection, &find_query, NULL, NULL);
2215 query_done = true;
2216
2217 /* Do something with the results */
2218 while (mongoc_cursor_next (cursor, &doc)) {
2219 print_res (doc);
2220 }
2221
2222 if (mongoc_cursor_error (cursor, &error)) {
2223 fprintf (stderr, "ERROR: %s\n", error.message);
2224 res = false;
2225 goto cleanup;
2226 }
2227
2228 cleanup:
2229 /* cleanup */
2230 if (query_done) {
2231 mongoc_cursor_destroy (cursor);
2232 mongoc_collection_destroy (out_collection);
2233 }
2234
2235 bson_destroy (&reply);
2236 bson_destroy (command);
2237
2238 return res;
2239 }
2240
2241
2242 mapReduce - more complicated example
2243 You must have replica set running for this.
2244
2245 In this example we contact a secondary in the replica set and do an
2246 "inline" map reduce, so the results are returned immediately:
2247 map-reduce-advanced.c.INDENT 0.0
2248
2249 bool
2250 map_reduce_advanced (mongoc_database_t *database)
2251 {
2252 bson_t *command;
2253 bson_error_t error;
2254 bool res = true;
2255 mongoc_cursor_t *cursor;
2256 mongoc_read_prefs_t *read_pref;
2257 const bson_t *doc;
2258
2259 /* Construct the mapReduce command */
2260 /* Other arguments can also be specified here, like "query" or "limit"
2261 and so on */
2262
2263 /* Read the results inline from a secondary replica */
2264 command = BCON_NEW ("mapReduce",
2265 BCON_UTF8 (COLLECTION_NAME),
2266 "map",
2267 BCON_CODE (MAPPER),
2268 "reduce",
2269 BCON_CODE (REDUCER),
2270 "out",
2271 "{",
2272 "inline",
2273 "1",
2274 "}");
2275
2276 read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
2277 cursor = mongoc_database_command (
2278 database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref);
2279
2280 /* Do something with the results */
2281 while (mongoc_cursor_next (cursor, &doc)) {
2282 print_res (doc);
2283 }
2284
2285 if (mongoc_cursor_error (cursor, &error)) {
2286 fprintf (stderr, "ERROR: %s\n", error.message);
2287 res = false;
2288 }
2289
2290 mongoc_cursor_destroy (cursor);
2291 mongoc_read_prefs_destroy (read_pref);
2292 bson_destroy (command);
2293
2294 return res;
2295 }
2296
2297
2298 Running the Examples
2299 Here's how to run the example code basic-aggregation.c.INDENT 0.0
2300
2301 /*
2302 * Copyright 2016 MongoDB, Inc.
2303 *
2304 * Licensed under the Apache License, Version 2.0 (the "License");
2305 * you may not use this file except in compliance with the License.
2306 * You may obtain a copy of the License at
2307 *
2308 * http://www.apache.org/licenses/LICENSE-2.0
2309 *
2310 * Unless required by applicable law or agreed to in writing, software
2311 * distributed under the License is distributed on an "AS IS" BASIS,
2312 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2313 * See the License for the specific language governing permissions and
2314 * limitations under the License.
2315 */
2316
2317
2318 #include <mongoc/mongoc.h>
2319 #include <stdio.h>
2320
2321
2322 #include "constants.c"
2323
2324 #include "../doc-common-insert.c"
2325 #include "distinct.c"
2326 #include "map-reduce-basic.c"
2327 #include "map-reduce-advanced.c"
2328
2329
2330 int
2331 main (int argc, char *argv[])
2332 {
2333 mongoc_database_t *database = NULL;
2334 mongoc_client_t *client = NULL;
2335 mongoc_collection_t *collection = NULL;
2336 mongoc_uri_t *uri = NULL;
2337 bson_error_t error;
2338 char *host_and_port = NULL;
2339 int exit_code = EXIT_FAILURE;
2340
2341 if (argc != 2) {
2342 fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]);
2343 fprintf (stderr,
2344 "the connection string can be of the following forms:\n");
2345 fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
2346 fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
2347 fprintf (stderr,
2348 "mongodb://user:pass@localhost:27017\t"
2349 "local machine on port 27017, and authenticate with username "
2350 "user and password pass\n");
2351 return exit_code;
2352 }
2353
2354 mongoc_init ();
2355
2356 if (strncmp (argv[1], "mongodb://", 10) == 0) {
2357 host_and_port = bson_strdup (argv[1]);
2358 } else {
2359 host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
2360 }
2361
2362 uri = mongoc_uri_new_with_error (host_and_port, &error);
2363 if (!uri) {
2364 fprintf (stderr,
2365 "failed to parse URI: %s\n"
2366 "error message: %s\n",
2367 host_and_port,
2368 error.message);
2369 goto cleanup;
2370 }
2371
2372 client = mongoc_client_new_from_uri (uri);
2373 if (!client) {
2374 goto cleanup;
2375 }
2376
2377 mongoc_client_set_error_api (client, 2);
2378 database = mongoc_client_get_database (client, "test");
2379 collection = mongoc_database_get_collection (database, COLLECTION_NAME);
2380
2381 printf ("Inserting data\n");
2382 if (!insert_data (collection)) {
2383 goto cleanup;
2384 }
2385
2386 printf ("distinct\n");
2387 if (!distinct (database)) {
2388 goto cleanup;
2389 }
2390
2391 printf ("map reduce\n");
2392 if (!map_reduce_basic (database)) {
2393 goto cleanup;
2394 }
2395
2396 printf ("more complicated map reduce\n");
2397 if (!map_reduce_advanced (database)) {
2398 goto cleanup;
2399 }
2400
2401 exit_code = EXIT_SUCCESS;
2402
2403 cleanup:
2404 if (collection) {
2405 mongoc_collection_destroy (collection);
2406 }
2407
2408 if (database) {
2409 mongoc_database_destroy (database);
2410 }
2411
2412 if (client) {
2413 mongoc_client_destroy (client);
2414 }
2415
2416 if (uri) {
2417 mongoc_uri_destroy (uri);
2418 }
2419
2420 if (host_and_port) {
2421 bson_free (host_and_port);
2422 }
2423
2424 mongoc_cleanup ();
2425 return exit_code;
2426 }
2427
2428
2429If you want to try the advanced map reduce example with a secondary, start a
2430replica set (instructions for how to do this can be found here).
2431
2432Otherwise, just start an instance of MongoDB:
2433
2434 $ mongod
2435
2436 Now compile and run the example program:
2437
2438 $ cd examples/basic_aggregation/
2439 $ gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0)
2440 $ ./agg-example localhost
2441
2442 Inserting data
2443 distinct
2444 Next double: 2.000000
2445 Next double: 3.000000
2446 map reduce
2447 { "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
2448 { "_id" : "cat", "value" : 63 }
2449 { "_id" : "dog", "value" : 42 }
2450 { "_id" : "mouse", "value" : 21 }
2451 more complicated map reduce
2452 { "results" : [ { "_id" : "cat", "value" : 63 }, { "_id" : "dog", "value" : 42 }, { "_id" : "mouse", "value" : 21 } ], "timeMillis" : 14, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
2453
2455 Download and install libmongoc on your system, then open Visual Studio,
2456 select "File→New→Project...", and create a new Win32 Console Applica‐
2457 tion. [image]
2458
2459 Remember to switch the platform from 32-bit to 64-bit: [image]
2460
2461 Right-click on your console application in the Solution Explorer and
2462 select "Properties". Choose to edit properties for "All Configura‐
2463 tions", expand the "C/C++" options and choose "General". Add to the
2464 "Additional Include Directories" these paths:
2465
2466 C:\mongo-c-driver\include\libbson-1.0
2467 C:\mongo-c-driver\include\libmongoc-1.0
2468 [image]
2469
2470 (If you chose a different CMAKE_INSTALL_PREFIX when you ran CMake, your
2471 include paths will be different.)
2472
2473 Also in the Properties dialog, expand the "Linker" options and choose
2474 "Input", and add to the "Additional Dependencies" these libraries:
2475
2476 C:\mongo-c-driver\lib\bson-1.0.lib
2477 C:\mongo-c-driver\lib\mongoc-1.0.lib
2478 [image]
2479
2480 Adding these libraries as dependencies provides linker symbols to build
2481 your application, but to actually run it, libbson's and libmongoc's
2482 DLLs must be in your executable path. Select "Debugging" in the Proper‐
2483 ties dialog, and set the "Environment" option to:
2484
2485 PATH=c:/mongo-c-driver/bin
2486 [image]
2487
2488 Finally, include "mongoc/mongoc.h" in your project's "stdafx.h":
2489
2490 #include <mongoc/mongoc.h>
2491
2492 Static linking
2493 Following the instructions above, you have dynamically linked your
2494 application to the libbson and libmongoc DLLs. This is usually the
2495 right choice. If you want to link statically instead, update your
2496 "Additional Dependencies" list by removing bson-1.0.lib and mon‐
2497 goc-1.0.lib and replacing them with these libraries:
2498
2499 C:\mongo-c-driver\lib\bson-static-1.0.lib
2500 C:\mongo-c-driver\lib\mongoc-static-1.0.lib
2501 ws2_32.lib
2502 Secur32.lib
2503 Crypt32.lib
2504 BCrypt.lib
2505 [image]
2506
2507 (To explain the purpose of each library: bson-static-1.0.lib and mon‐
2508 goc-static-1.0.lib are static archives of the driver code. The socket
2509 library ws2_32 is required by libbson, which uses the socket routine
2510 gethostname to help guarantee ObjectId uniqueness. The BCrypt library
2511 is used by libmongoc for SSL connections to MongoDB, and Secur32 and
2512 Crypt32 are required for enterprise authentication methods like Ker‐
2513 beros.)
2514
2515 Finally, define two preprocessor symbols before including mongoc/mon‐
2516 goc.h in your stdafx.h:
2517
2518 #define BSON_STATIC
2519 #define MONGOC_STATIC
2520 #include <mongoc/mongoc.h>
2521
2522 Making these changes to your project is only required for static link‐
2523 ing; for most people, the dynamic-linking instructions above are pre‐
2524 ferred.
2525
2526 Next Steps
2527 Now you can build and debug applications in Visual Studio that use
2528 libbson and libmongoc. Proceed to making-a-connection in the tutorial
2529 to learn how connect to MongoDB and perform operations.
2530
2532 To create indexes on a MongoDB collection, execute the createIndexes
2533 command with a command function like mongoc_database_write_com‐
2534 mand_with_opts or mongoc_collection_write_command_with_opts. See the
2535 MongoDB Manual entry for the createIndexes command for details.
2536
2537 Example
2538 example-create-indexes.c.INDENT 0.0
2539
2540 /* gcc example-create-indexes.c -o example-create-indexes $(pkg-config --cflags
2541 * --libs libmongoc-1.0) */
2542
2543 /* ./example-create-indexes [CONNECTION_STRING [COLLECTION_NAME]] */
2544
2545 #include <mongoc/mongoc.h>
2546 #include <stdio.h>
2547 #include <stdlib.h>
2548
2549 int
2550 main (int argc, char *argv[])
2551 {
2552 mongoc_client_t *client;
2553 const char *uri_string =
2554 "mongodb://127.0.0.1/?appname=create-indexes-example";
2555 mongoc_uri_t *uri;
2556 mongoc_database_t *db;
2557 const char *collection_name = "test";
2558 bson_t keys;
2559 char *index_name;
2560 bson_t *create_indexes;
2561 bson_t reply;
2562 char *reply_str;
2563 bson_error_t error;
2564 bool r;
2565
2566 mongoc_init ();
2567
2568 if (argc > 1) {
2569 uri_string = argv[1];
2570 }
2571
2572 if (argc > 2) {
2573 collection_name = argv[2];
2574 }
2575
2576 uri = mongoc_uri_new_with_error (uri_string, &error);
2577 if (!uri) {
2578 fprintf (stderr,
2579 "failed to parse URI: %s\n"
2580 "error message: %s\n",
2581 uri_string,
2582 error.message);
2583 return EXIT_FAILURE;
2584 }
2585
2586 client = mongoc_client_new_from_uri (uri);
2587 if (!client) {
2588 return EXIT_FAILURE;
2589 }
2590
2591 mongoc_client_set_error_api (client, 2);
2592 db = mongoc_client_get_database (client, "test");
2593
2594 /* ascending index on field "x" */
2595 bson_init (&keys);
2596 BSON_APPEND_INT32 (&keys, "x", 1);
2597 index_name = mongoc_collection_keys_to_index_string (&keys);
2598 create_indexes = BCON_NEW ("createIndexes",
2599 BCON_UTF8 (collection_name),
2600 "indexes",
2601 "[",
2602 "{",
2603 "key",
2604 BCON_DOCUMENT (&keys),
2605 "name",
2606 BCON_UTF8 (index_name),
2607 "}",
2608 "]");
2609
2610 r = mongoc_database_write_command_with_opts (
2611 db, create_indexes, NULL /* opts */, &reply, &error);
2612
2613 reply_str = bson_as_json (&reply, NULL);
2614 printf ("%s\n", reply_str);
2615
2616 if (!r) {
2617 fprintf (stderr, "Error in createIndexes: %s\n", error.message);
2618 }
2619
2620 bson_free (index_name);
2621 bson_free (reply_str);
2622 bson_destroy (&reply);
2623 bson_destroy (create_indexes);
2624 mongoc_database_destroy (db);
2625 mongoc_uri_destroy (uri);
2626 mongoc_client_destroy (client);
2627
2628 mongoc_cleanup ();
2629
2630 return r ? EXIT_SUCCESS : EXIT_FAILURE;
2631 }
2632
2633
2635 GDB
2636 This repository contains a .gdbinit file that contains helper functions
2637 to aid debugging of data structures. GDB will load this file
2638 automatically if you have added the directory which contains the
2639 .gdbinit file to GDB's auto-load safe-path, and you start GDB from the
2640 directory which holds the .gdbinit file.
2641
2642 You can see the safe-path with show auto-load safe-path on a GDB
2643 prompt. You can configure it by setting it in ~/.gdbinit with:
2644
2645 add-auto-load-safe-path /path/to/mongo-c-driver
2646
2647 If you haven't added the path to your auto-load safe-path, or start GDB
2648 in another directory, load the file with:
2649
2650 source path/to/mongo-c-driver/.gdbinit
2651
2652 The .gdbinit file defines the printbson function, which shows the con‐
2653 tents of a bson_t * variable. If you have a local bson_t, then you
2654 must prefix the variable with a &.
2655
2656 An example GDB session looks like:
2657
2658 (gdb) printbson bson
2659 ALLOC [0x555556cd7310 + 0] (len=475)
2660 {
2661 'bool' : true,
2662 'int32' : NumberInt("42"),
2663 'int64' : NumberLong("3000000042"),
2664 'string' : "Stŕìñg",
2665 'objectId' : ObjectID("5A1442F3122D331C3C6757E1"),
2666 'utcDateTime' : UTCDateTime(1511277299031),
2667 'arrayOfInts' : [
2668 '0' : NumberInt("1"),
2669 '1' : NumberInt("2")
2670 ],
2671 'embeddedDocument' : {
2672 'arrayOfStrings' : [
2673 '0' : "one",
2674 '1' : "two"
2675 ],
2676 'double' : 2.718280,
2677 'notherDoc' : {
2678 'true' : NumberInt("1"),
2679 'false' : false
2680 }
2681 },
2682 'binary' : Binary("02", "3031343532333637"),
2683 'regex' : Regex("@[a-z]+@", "im"),
2684 'null' : null,
2685 'js' : JavaScript("print foo"),
2686 'jsws' : JavaScript("print foo") with scope: {
2687 'f' : NumberInt("42"),
2688 'a' : [
2689 '0' : 3.141593,
2690 '1' : 2.718282
2691 ]
2692 },
2693 'timestamp' : Timestamp(4294967295, 4294967295),
2694 'double' : 3.141593
2695 }
2696
2697 LLDB
2698 This repository also includes a script that customizes LLDB's standard
2699 print command to print a bson_t or bson_t * as JSON:
2700
2701 (lldb) print b
2702 (bson_t) $0 = {"x": 1, "y": 2}
2703
2704 The custom bson command provides more options:
2705
2706 (lldb) bson --verbose b
2707 len=19
2708 flags=INLINE|STATIC
2709 {
2710 "x": 1,
2711 "y": 2
2712 }
2713 (lldb) bson --raw b
2714 '\x13\x00\x00\x00\x10x\x00\x01\x00\x00\x00\x10y\x00\x02\x00\x00\x00\x00'
2715
2716 Type help bson for a list of options.
2717
2718 The script requires a build of libbson with debug symbols, and an
2719 installation of PyMongo. Install PyMongo with:
2720
2721 python -m pip install pymongo
2722
2723 If you see "No module named pip" then you must install pip, then run
2724 the previous command again.
2725
2726 Create a file ~/.lldbinit containing:
2727
2728 command script import /path/to/mongo-c-driver/lldb_bson.py
2729
2730 If you see "bson command installed by lldb_bson" at the beginning of
2731 your LLDB session, you've installed the script correctly.
2732
2734 MongoDB, Inc
2735
2737 2017-present, MongoDB, Inc
2738
2739
2740
2741
27421.13.1 Jan 24, 2019 MONGOC_GUIDES(3)