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