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