1MONGOC_GUIDES(3) libmongoc MONGOC_GUIDES(3)
2
3
4
6 mongoc_guides - Guides
7
9 Configuration with URI options
10 Enable TLS by including tls=true the URI.
11
12 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
13 mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
14
15 mongoc_client_t *client = mongoc_client_new_from_uri (uri);
16
17 The following URI options may be used to further configure TLS:
18
19 ┌────────────────────┬─────────────────────┬─────────────────────┐
20 │Constant │ Key │ Description │
21 ├────────────────────┼─────────────────────┼─────────────────────┤
22 │MONGOC_URI_TLS │ tls │ {true|false}, indi‐ │
23 │ │ │ cating if TLS must │
24 │ │ │ be used. │
25 ├────────────────────┼─────────────────────┼─────────────────────┤
26 │MONGOC_URI_TLSCER‐ │ tlscertificatekey‐ │ Path to PEM format‐ │
27 │TIFICATEKEYFILE │ file │ ted Private Key, │
28 │ │ │ with its Public │
29 │ │ │ Certificate con‐ │
30 │ │ │ catenated at the │
31 │ │ │ end. │
32 ├────────────────────┼─────────────────────┼─────────────────────┤
33 │MONGOC_URI_TLSCER‐ │ tlscertificatekey‐ │ The password, if │
34 │TIFICATEKEYPASSWORD │ password │ any, to use to un‐ │
35 │ │ │ lock encrypted Pri‐ │
36 │ │ │ vate Key. │
37 ├────────────────────┼─────────────────────┼─────────────────────┤
38 │MON‐ │ tlscafile │ One, or a bundle │
39 │GOC_URI_TLSCAFILE │ │ of, Certificate Au‐ │
40 │ │ │ thorities whom │
41 │ │ │ should be consid‐ │
42 │ │ │ ered to be trusted. │
43 ├────────────────────┼─────────────────────┼─────────────────────┤
44 │MONGOC_URI_TLSAL‐ │ tlsallowinvalidcer‐ │ Accept and ignore │
45 │LOWINVALIDCERTIFI‐ │ tificates │ certificate verifi‐ │
46 │CATES │ │ cation errors (e.g. │
47 │ │ │ untrusted issuer, │
48 │ │ │ expired, etc.) │
49 ├────────────────────┼─────────────────────┼─────────────────────┤
50 │MONGOC_URI_TLSAL‐ │ tlsallowinvalid‐ │ Ignore hostname │
51 │LOWINVALIDHOSTNAMES │ hostnames │ verification of the │
52 │ │ │ certificate (e.g. │
53 │ │ │ Man In The Middle, │
54 │ │ │ using valid cer‐ │
55 │ │ │ tificate, but is‐ │
56 │ │ │ sued for another │
57 │ │ │ hostname) │
58 └────────────────────┴─────────────────────┴─────────────────────┘
59
60
61
62
63
64
65
66
67 │MONGOC_URI_TLSINSE‐ │ tlsinsecure │ {true|false}, indi‐ │
68 │CURE │ │ cating if insecure │
69 │ │ │ TLS options should │
70 │ │ │ be used. Currently │
71 │ │ │ this implies MON‐ │
72 │ │ │ GOC_URI_TLSALLOWIN‐ │
73 │ │ │ VALIDCERTIFICATES │
74 │ │ │ and MONGOC_URI_TL‐ │
75 │ │ │ SALLOWINVALIDHOST‐ │
76 │ │ │ NAMES. │
77 ├────────────────────┼─────────────────────┼─────────────────────┤
78 │MONGOC_URI_TLSDIS‐ │ tlsdisablecertifi‐ │ {true|false}, indi‐ │
79 │ABLECERTIFICATERE‐ │ caterevocationcheck │ cates if revocation │
80 │VOCATIONCHECK │ │ checking (CRL / │
81 │ │ │ OCSP) should be │
82 │ │ │ disabled. │
83 ├────────────────────┼─────────────────────┼─────────────────────┤
84 │MONGOC_URI_TLSDIS‐ │ tlsdisableocspend‐ │ {true|false}, indi‐ │
85 │ABLEOCSPEND‐ │ pointcheck │ cates if OCSP re‐ │
86 │POINTCHECK │ │ sponder endpoints │
87 │ │ │ should not be re‐ │
88 │ │ │ quested when an │
89 │ │ │ OCSP response is │
90 │ │ │ not stapled. │
91 └────────────────────┴─────────────────────┴─────────────────────┘
92
93 Configuration with mongoc_ssl_opt_t
94 Alternatively, the mongoc_ssl_opt_t struct may be used to configure TLS
95 with mongoc_client_set_ssl_opts() or mongoc_client_pool_set_ssl_opts().
96 Most of the configurable options can be set using the Connection String
97 URI.
98
99 ┌───────────────────────┬──────────────────────────┐
100 │mongoc_ssl_opt_t key │ URI key │
101 ├───────────────────────┼──────────────────────────┤
102 │pem_file │ tlsClientCertificateKey‐ │
103 │ │ File │
104 ├───────────────────────┼──────────────────────────┤
105 │pem_pwd │ tlsClientCertificateKey‐ │
106 │ │ Password │
107 ├───────────────────────┼──────────────────────────┤
108 │ca_file │ tlsCAFile │
109 ├───────────────────────┼──────────────────────────┤
110 │weak_cert_validation │ tlsAllowInvalidCertifi‐ │
111 │ │ cates │
112 ├───────────────────────┼──────────────────────────┤
113 │allow_invalid_hostname │ tlsAllowInvalidHostnames │
114 └───────────────────────┴──────────────────────────┘
115
116 The only exclusions are crl_file and ca_dir. Those may only be set with
117 mongoc_ssl_opt_t.
118
119 Client Authentication
120 When MongoDB is started with TLS enabled, it will by default require
121 the client to provide a client certificate issued by a certificate au‐
122 thority specified by --tlsCAFile, or an authority trusted by the native
123 certificate store in use on the server.
124
125 To provide the client certificate, set the tlsCertificateKeyFile in the
126 URI to a PEM armored certificate file.
127
128 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
129 mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
130 mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "/path/to/client-certificate.pem");
131
132 mongoc_client_t *client = mongoc_client_new_from_uri (uri);
133
134 Server Certificate Verification
135 The MongoDB C Driver will automatically verify the validity of the
136 server certificate, such as issued by configured Certificate Authority,
137 hostname validation, and expiration.
138
139 To overwrite this behavior, it is possible to disable hostname valida‐
140 tion, OCSP endpoint revocation checking, revocation checking entirely,
141 and allow invalid certificates.
142
143 This behavior is controlled using the tlsAllowInvalidHostnames, tlsDis‐
144 ableOCSPEndpointCheck, tlsDisableCertificateRevocationCheck, and tlsAl‐
145 lowInvalidCertificates options respectively. By default, all are set to
146 false.
147
148 It is not recommended to change these defaults as it exposes the client
149 to Man In The Middle attacks (when tlsAllowInvalidHostnames is set),
150 invalid certificates (when tlsAllowInvalidCertificates is set), or po‐
151 tentially revoked certificates (when tlsDisableOCSPEndpointCheck or
152 tlsDisableCertificateRevocationCheck are set).
153
154 Supported Libraries
155 By default, libmongoc will attempt to find a supported TLS library and
156 enable TLS support. This is controlled by the cmake flag ENABLE_SSL,
157 which is set to AUTO by default. Valid values are:
158
159 • AUTO the default behavior. Link to the system's native TLS library,
160 or attempt to find OpenSSL.
161
162 • DARWIN link to Secure Transport, the native TLS library on macOS.
163
164 • WINDOWS link to Secure Channel, the native TLS library on Windows.
165
166 • OPENSSL link to OpenSSL (libssl). An optional install path may be
167 specified with OPENSSL_ROOT.
168
169 • LIBRESSL link to LibreSSL's libtls. (LibreSSL's compatible libssl may
170 be linked to by setting OPENSSL).
171
172 • OFF disable TLS support.
173
174 OpenSSL
175 The MongoDB C Driver uses OpenSSL, if available, on Linux and Unix
176 platforms (besides macOS). Industry best practices and some regulations
177 require the use of TLS 1.1 or newer, which requires at least OpenSSL
178 1.0.1. Check your OpenSSL version like so:
179
180 $ openssl version
181
182 Ensure your system's OpenSSL is a recent version (at least 1.0.1), or
183 install a recent version in a non-system path and build against it
184 with:
185
186 cmake -DOPENSSL_ROOT_DIR=/absolute/path/to/openssl
187
188 When compiled against OpenSSL, the driver will attempt to load the sys‐
189 tem default certificate store, as configured by the distribution. That
190 can be overridden by setting the tlsCAFile URI option or with the
191 fields ca_file and ca_dir in the mongoc_ssl_opt_t.
192
193 The Online Certificate Status Protocol (OCSP) (see RFC 6960) is fully
194 supported when using OpenSSL 1.0.1+ with the following notes:
195
196 • When a crl_file is set with mongoc_ssl_opt_t, and the crl_file re‐
197 vokes the server's certificate, the certificate is considered revoked
198 (even if the certificate has a valid stapled OCSP response)
199
200 LibreSSL / libtls
201 The MongoDB C Driver supports LibreSSL through the use of OpenSSL com‐
202 patibility checks when configured to compile against openssl. It also
203 supports the new libtls library when configured to build against li‐
204 bressl.
205
206 When compiled against the Windows native libraries, the crl_file option
207 of a mongoc_ssl_opt_t is not supported, and will issue an error if
208 used.
209
210 Setting tlsDisableOCSPEndpointCheck and tlsDisableCertificateRevoca‐
211 tionCheck has no effect.
212
213 The Online Certificate Status Protocol (OCSP) (see RFC 6960) is par‐
214 tially supported with the following notes:
215
216 • The Must-Staple extension (see RFC 7633) is ignored. Connection may
217 continue if a Must-Staple certificate is presented with no stapled
218 response (unless the client receives a revoked response from an OCSP
219 responder).
220
221 • Connection will continue if a Must-Staple certificate is presented
222 without a stapled response and the OCSP responder is down.
223
224 Native TLS Support on Windows (Secure Channel)
225 The MongoDB C Driver supports the Windows native TLS library (Secure
226 Channel, or SChannel), and its native crypto library (Cryptography API:
227 Next Generation, or CNG).
228
229 When compiled against the Windows native libraries, the ca_dir option
230 of a mongoc_ssl_opt_t is not supported, and will issue an error if
231 used.
232
233 Encrypted PEM files (e.g., setting tlsCertificateKeyPassword) are also
234 not supported, and will result in error when attempting to load them.
235
236 When tlsCAFile is set, the driver will only allow server certificates
237 issued by the authority (or authorities) provided. When no tlsCAFile is
238 set, the driver will look up the Certificate Authority using the System
239 Local Machine Root certificate store to confirm the provided certifi‐
240 cate.
241
242 When crl_file is set with mongoc_ssl_opt_t, the driver will import the
243 revocation list to the System Local Machine Root certificate store.
244
245 Setting tlsDisableOCSPEndpointCheck has no effect.
246
247 The Online Certificate Status Protocol (OCSP) (see RFC 6960) is par‐
248 tially supported with the following notes:
249
250 • The Must-Staple extension (see RFC 7633) is ignored. Connection may
251 continue if a Must-Staple certificate is presented with no stapled
252 response (unless the client receives a revoked response from an OCSP
253 responder).
254
255 • When a crl_file is set with mongoc_ssl_opt_t, and the crl_file re‐
256 vokes the server's certificate, the OCSP response takes precedence.
257 E.g. if the server presents a certificate with a valid stapled OCSP
258 response, the certificate is considered valid even if the crl_file
259 marks it as revoked.
260
261 • Connection will continue if a Must-Staple certificate is presented
262 without a stapled response and the OCSP responder is down.
263
264 Native TLS Support on macOS / Darwin (Secure Transport)
265 The MongoDB C Driver supports the Darwin (OS X, macOS, iOS, etc.) na‐
266 tive TLS library (Secure Transport), and its native crypto library
267 (Common Crypto, or CC).
268
269 When compiled against Secure Transport, the ca_dir and crl_file options
270 of a mongoc_ssl_opt_t are not supported. An error is issued if either
271 are used.
272
273 When tlsCAFile is set, the driver will only allow server certificates
274 issued by the authority (or authorities) provided. When no tlsCAFile is
275 set, the driver will use the Certificate Authorities in the currently
276 unlocked keychains.
277
278 Setting tlsDisableOCSPEndpointCheck and tlsDisableCertificateRevoca‐
279 tionCheck has no effect.
280
281 The Online Certificate Status Protocol (OCSP) (see RFC 6960) is par‐
282 tially supported with the following notes.
283
284 • The Must-Staple extension (see RFC 7633) is ignored. Connection may
285 continue if a Must-Staple certificate is presented with no stapled
286 response (unless the client receives a revoked response from an OCSP
287 responder).
288
289 • Connection will continue if a Must-Staple certificate is presented
290 without a stapled response and the OCSP responder is down.
291
293 Drivers for some other languages provide helper functions to perform
294 certain common tasks. In the C Driver we must explicitly build commands
295 to send to the server.
296
297 Setup
298 First we'll write some code to insert sample data:
299
300 doc-common-insert.c
301
302 /* Don't try to compile this file on its own. It's meant to be #included
303 by example code */
304
305 /* Insert some sample data */
306 bool
307 insert_data (mongoc_collection_t *collection)
308 {
309 mongoc_bulk_operation_t *bulk;
310 enum N { ndocs = 4 };
311 bson_t *docs[ndocs];
312 bson_error_t error;
313 int i = 0;
314 bool ret;
315
316 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
317
318 docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
319 docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
320 docs[2] = BCON_NEW (
321 "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
322 docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
323
324 for (i = 0; i < ndocs; i++) {
325 mongoc_bulk_operation_insert (bulk, docs[i]);
326 bson_destroy (docs[i]);
327 docs[i] = NULL;
328 }
329
330 ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
331
332 if (!ret) {
333 fprintf (stderr, "Error inserting data: %s\n", error.message);
334 }
335
336 mongoc_bulk_operation_destroy (bulk);
337 return ret;
338 }
339
340 /* A helper which we'll use a lot later on */
341 void
342 print_res (const bson_t *reply)
343 {
344 char *str;
345 BSON_ASSERT (reply);
346 str = bson_as_canonical_extended_json (reply, NULL);
347 printf ("%s\n", str);
348 bson_free (str);
349 }
350
351
352 explain Command
353 This is how to use the explain command in MongoDB 3.2+:
354
355 explain.c
356
357 bool
358 explain (mongoc_collection_t *collection)
359 {
360 bson_t *command;
361 bson_t reply;
362 bson_error_t error;
363 bool res;
364
365 command = BCON_NEW ("explain",
366 "{",
367 "find",
368 BCON_UTF8 (COLLECTION_NAME),
369 "filter",
370 "{",
371 "x",
372 BCON_INT32 (1),
373 "}",
374 "}");
375 res = mongoc_collection_command_simple (
376 collection, command, NULL, &reply, &error);
377 if (!res) {
378 fprintf (stderr, "Error with explain: %s\n", error.message);
379 goto cleanup;
380 }
381
382 /* Do something with the reply */
383 print_res (&reply);
384
385 cleanup:
386 bson_destroy (&reply);
387 bson_destroy (command);
388 return res;
389 }
390
391
392 Running the Examples
393 common-operations.c
394
395 /*
396 * Copyright 2016 MongoDB, Inc.
397 *
398 * Licensed under the Apache License, Version 2.0 (the "License");
399 * you may not use this file except in compliance with the License.
400 * You may obtain a copy of the License at
401 *
402 * http://www.apache.org/licenses/LICENSE-2.0
403 *
404 * Unless required by applicable law or agreed to in writing, software
405 * distributed under the License is distributed on an "AS IS" BASIS,
406 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
407 * See the License for the specific language governing permissions and
408 * limitations under the License.
409 */
410
411
412 #include <mongoc/mongoc.h>
413 #include <stdio.h>
414
415
416 const char *COLLECTION_NAME = "things";
417
418 #include "../doc-common-insert.c"
419 #include "explain.c"
420
421
422 int
423 main (int argc, char *argv[])
424 {
425 mongoc_database_t *database = NULL;
426 mongoc_client_t *client = NULL;
427 mongoc_collection_t *collection = NULL;
428 mongoc_uri_t *uri = NULL;
429 bson_error_t error;
430 char *host_and_port;
431 int res = 0;
432
433 if (argc < 2 || argc > 3) {
434 fprintf (stderr,
435 "usage: %s MONGOD-1-CONNECTION-STRING "
436 "[MONGOD-2-HOST-NAME:MONGOD-2-PORT]\n",
437 argv[0]);
438 fprintf (stderr,
439 "MONGOD-1-CONNECTION-STRING can be "
440 "of the following forms:\n");
441 fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
442 fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
443 fprintf (stderr,
444 "mongodb://user:pass@localhost:27017\t"
445 "local machine on port 27017, and authenticate with username "
446 "user and password pass\n");
447 return EXIT_FAILURE;
448 }
449
450 mongoc_init ();
451
452 if (strncmp (argv[1], "mongodb://", 10) == 0) {
453 host_and_port = bson_strdup (argv[1]);
454 } else {
455 host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
456 }
457
458 uri = mongoc_uri_new_with_error (host_and_port, &error);
459 if (!uri) {
460 fprintf (stderr,
461 "failed to parse URI: %s\n"
462 "error message: %s\n",
463 host_and_port,
464 error.message);
465 res = EXIT_FAILURE;
466 goto cleanup;
467 }
468
469 client = mongoc_client_new_from_uri (uri);
470 if (!client) {
471 res = EXIT_FAILURE;
472 goto cleanup;
473 }
474
475 mongoc_client_set_error_api (client, 2);
476 database = mongoc_client_get_database (client, "test");
477 collection = mongoc_database_get_collection (database, COLLECTION_NAME);
478
479 printf ("Inserting data\n");
480 if (!insert_data (collection)) {
481 res = EXIT_FAILURE;
482 goto cleanup;
483 }
484
485 printf ("explain\n");
486 if (!explain (collection)) {
487 res = EXIT_FAILURE;
488 goto cleanup;
489 }
490
491 cleanup:
492 if (collection) {
493 mongoc_collection_destroy (collection);
494 }
495
496 if (database) {
497 mongoc_database_destroy (database);
498 }
499
500 if (client) {
501 mongoc_client_destroy (client);
502 }
503
504 if (uri) {
505 mongoc_uri_destroy (uri);
506 }
507
508 bson_free (host_and_port);
509 mongoc_cleanup ();
510 return res;
511 }
512
513
514 First launch two separate instances of mongod (must be done from sepa‐
515 rate shells):
516
517 $ mongod
518
519 $ mkdir /tmp/db2
520 $ mongod --dbpath /tmp/db2 --port 27018 # second instance
521
522 Now compile and run the example program:
523
524 $ cd examples/common_operations/$ gcc -Wall -o example common-operations.c $(pkg-config --cflags --libs libmongoc-1.0)$ ./example localhost:27017 localhost:27018
525 Inserting data
526 explain
527 {
528 "executionStats" : {
529 "allPlansExecution" : [],
530 "executionStages" : {
531 "advanced" : 19,
532 "direction" : "forward" ,
533 "docsExamined" : 76,
534 "executionTimeMillisEstimate" : 0,
535 "filter" : {
536 "x" : {
537 "$eq" : 1
538 }
539 },
540 "invalidates" : 0,
541 "isEOF" : 1,
542 "nReturned" : 19,
543 "needTime" : 58,
544 "needYield" : 0,
545 "restoreState" : 0,
546 "saveState" : 0,
547 "stage" : "COLLSCAN" ,
548 "works" : 78
549 },
550 "executionSuccess" : true,
551 "executionTimeMillis" : 0,
552 "nReturned" : 19,
553 "totalDocsExamined" : 76,
554 "totalKeysExamined" : 0
555 },
556 "ok" : 1,
557 "queryPlanner" : {
558 "indexFilterSet" : false,
559 "namespace" : "test.things",
560 "parsedQuery" : {
561 "x" : {
562 "$eq" : 1
563 }
564 },
565 "plannerVersion" : 1,
566 "rejectedPlans" : [],
567 "winningPlan" : {
568 "direction" : "forward" ,
569 "filter" : {
570 "x" : {
571 "$eq" : 1
572 }
573 },
574 "stage" : "COLLSCAN"
575 }
576 },
577 "serverInfo" : {
578 "gitVersion" : "05552b562c7a0b3143a729aaa0838e558dc49b25" ,
579 "host" : "MacBook-Pro-57.local",
580 "port" : 27017,
581 "version" : "3.2.6"
582 }
583 }
584
586 The following guide contains information specific to certain types of
587 MongoDB configurations.
588
589 For an example of connecting to a simple standalone server, see the Tu‐
590 torial. To establish a connection with authentication options enabled,
591 see the Authentication page.
592
593 Connecting to a Replica Set
594 Connecting to a replica set is much like connecting to a standalone
595 MongoDB server. Simply specify the replica set name using the ?repli‐
596 caSet=myreplset URI option.
597
598 #include <bson/bson.h>
599 #include <mongoc/mongoc.h>
600
601 int
602 main (int argc, char *argv[])
603 {
604 mongoc_client_t *client;
605
606 mongoc_init ();
607
608 /* Create our MongoDB Client */
609 client = mongoc_client_new (
610 "mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset");
611
612 /* Do some work */
613 /* TODO */
614
615 /* Clean up */
616 mongoc_client_destroy (client);
617 mongoc_cleanup ();
618
619 return 0;
620 }
621
622 TIP:
623 Multiple hostnames can be specified in the MongoDB connection string
624 URI, with a comma separating hosts in the seed list.
625
626 It is recommended to use a seed list of members of the replica set
627 to allow the driver to connect to any node.
628
629 Connecting to a Sharded Cluster
630 To connect to a sharded cluster, specify the mongos nodes the client
631 should connect to. The C Driver will automatically detect that it has
632 connected to a mongos sharding server.
633
634 If more than one hostname is specified, a seed list will be created to
635 attempt failover between the mongos instances.
636
637 WARNING:
638 Specifying the replicaSet parameter when connecting to a mongos
639 sharding server is invalid.
640
641 #include <bson/bson.h>
642 #include <mongoc/mongoc.h>
643
644 int
645 main (int argc, char *argv[])
646 {
647 mongoc_client_t *client;
648
649 mongoc_init ();
650
651 /* Create our MongoDB Client */
652 client = mongoc_client_new ("mongodb://myshard01:27017/");
653
654 /* Do something with client ... */
655
656 /* Free the client */
657 mongoc_client_destroy (client);
658
659 mongoc_cleanup ();
660
661 return 0;
662 }
663
664 Connecting to an IPv6 Address
665 The MongoDB C Driver will automatically resolve IPv6 addresses from
666 host names. However, to specify an IPv6 address directly, wrap the ad‐
667 dress in [].
668
669 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://[::1]:27017");
670
671 Connecting with IPv4 and IPv6
672 If connecting to a hostname that has both IPv4 and IPv6 DNS records,
673 the behavior follows RFC-6555. A connection to the IPv6 address is at‐
674 tempted first. If IPv6 fails, then a connection is attempted to the
675 IPv4 address. If the connection attempt to IPv6 does not complete
676 within 250ms, then IPv4 is tried in parallel. Whichever succeeds con‐
677 nection first cancels the other. The successful DNS result is cached
678 for 10 minutes.
679
680 As a consequence, attempts to connect to a mongod only listening on
681 IPv4 may be delayed if there are both A (IPv4) and AAAA (IPv6) DNS
682 records associated with the host.
683
684 To avoid a delay, configure hostnames to match the MongoDB configura‐
685 tion. That is, only create an A record if the mongod is only listening
686 on IPv4.
687
688 Connecting to a UNIX Domain Socket
689 On UNIX-like systems, the C Driver can connect directly to a MongoDB
690 server using a UNIX domain socket. Pass the URL-encoded path to the
691 socket, which must be suffixed with .sock. For example, to connect to a
692 domain socket at /tmp/mongodb-27017.sock:
693
694 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://%2Ftmp%2Fmongodb-27017.sock");
695
696 Include username and password like so:
697
698 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://user:pass@%2Ftmp%2Fmongodb-27017.sock");
699
700 Connecting to a server over TLS
701 These are instructions for configuring TLS/SSL connections.
702
703 To run a server locally (on port 27017, for example):
704
705 $ mongod --port 27017 --tlsMode requireTLS --tlsCertificateKeyFile server.pem --tlsCAFile ca.pem
706
707 Add /?tls=true to the end of a client URI.
708
709 mongoc_client_t *client = NULL;
710 client = mongoc_client_new ("mongodb://localhost:27017/?tls=true");
711
712 MongoDB requires client certificates by default, unless the --tlsAllow‐
713 ConnectionsWithoutCertificates is provided. The C Driver can be config‐
714 ured to present a client certificate using the URI option tlsCertifi‐
715 cateKeyFile, which may be referenced through the constant MON‐
716 GOC_URI_TLSCERTIFICATEKEYFILE.
717
718 mongoc_client_t *client = NULL;
719 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/?tls=true");
720 mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "client.pem");
721
722 client = mongoc_client_new_from_uri (uri);
723
724 The client certificate provided by tlsCertificateKeyFile must be issued
725 by one of the server trusted Certificate Authorities listed in
726 --tlsCAFile, or issued by a CA in the native certificate store on the
727 server when omitted.
728
729 See configuring_tls for more information on the various TLS related op‐
730 tions.
731
732 Compressing data to and from MongoDB
733 MongoDB 3.4 added Snappy compression support, zlib compression in 3.6,
734 and zstd compression in 4.2. To enable compression support the client
735 must be configured with which compressors to use:
736
737 mongoc_client_t *client = NULL;
738 client = mongoc_client_new ("mongodb://localhost:27017/?compressors=snappy,zlib,zstd");
739
740 The compressors option specifies the priority order of compressors the
741 client wants to use. Messages are compressed if the client and server
742 share any compressors in common.
743
744 Note that the compressor used by the server might not be the same com‐
745 pressor as the client used. For example, if the client uses the con‐
746 nection string compressors=zlib,snappy the client will use zlib com‐
747 pression to send data (if possible), but the server might still reply
748 using snappy, depending on how the server was configured.
749
750 The driver must be built with zlib and/or snappy and/or zstd support to
751 enable compression support, any unknown (or not compiled in) compressor
752 value will be ignored. Note: to build with zstd requires cmake 3.12 or
753 higher.
754
755 Additional Connection Options
756 The full list of connection options can be found in the mongoc_uri_t
757 docs.
758
759 Certain socket/connection related options are not configurable:
760
761 ┌──────────────┬─────────────────────┬─────────────────────┐
762 │Option │ Description │ Value │
763 ├──────────────┼─────────────────────┼─────────────────────┤
764 │SO_KEEPALIVE │ TCP Keep Alive │ Enabled │
765 ├──────────────┼─────────────────────┼─────────────────────┤
766 │TCP_KEEPIDLE │ How long a connec‐ │ 120 seconds │
767 │ │ tion needs to re‐ │ │
768 │ │ main idle before │ │
769 │ │ TCP starts sending │ │
770 │ │ keepalive probes │ │
771 ├──────────────┼─────────────────────┼─────────────────────┤
772 │TCP_KEEPINTVL │ The time in seconds │ 10 seconds │
773 │ │ between TCP probes │ │
774 ├──────────────┼─────────────────────┼─────────────────────┤
775 │TCP_KEEPCNT │ How many probes to │ 9 probes │
776 │ │ send, without ac‐ │ │
777 │ │ knowledgement, be‐ │ │
778 │ │ fore dropping the │ │
779 │ │ connection │ │
780 ├──────────────┼─────────────────────┼─────────────────────┤
781 │TCP_NODELAY │ Send packets as │ Enabled (no buffer‐ │
782 │ │ soon as possible or │ ing) │
783 │ │ buffer small pack‐ │ │
784 │ │ ets (Nagle algo‐ │ │
785 │ │ rithm) │ │
786 └──────────────┴─────────────────────┴─────────────────────┘
787
789 The MongoDB C driver has two connection modes: single-threaded and
790 pooled. Single-threaded mode is optimized for embedding the driver
791 within languages like PHP. Multi-threaded programs should use pooled
792 mode: this mode minimizes the total connection count, and in pooled
793 mode background threads monitor the MongoDB server topology, so the
794 program need not block to scan it.
795
796 Single Mode
797 In single mode, your program creates a mongoc_client_t directly:
798
799 mongoc_client_t *client = mongoc_client_new (
800 "mongodb://hostA,hostB/?replicaSet=my_rs");
801
802 The client connects on demand when your program first uses it for a
803 MongoDB operation. Using a non-blocking socket per server, it begins a
804 check on each server concurrently, and uses the asynchronous poll or
805 select function to receive events from the sockets, until all have re‐
806 sponded or timed out. Put another way, in single-threaded mode the C
807 Driver fans out to begin all checks concurrently, then fans in once all
808 checks have completed or timed out. Once the scan completes, the client
809 executes your program's operation and returns.
810
811 In single mode, the client re-scans the server topology roughly once
812 per minute. If more than a minute has elapsed since the previous scan,
813 the next operation on the client will block while the client completes
814 its scan. This interval is configurable with heartbeatFrequencyMS in
815 the connection string. (See mongoc_uri_t.)
816
817 A single client opens one connection per server in your topology: these
818 connections are used both for scanning the topology and performing nor‐
819 mal operations.
820
821 Pooled Mode
822 To activate pooled mode, create a mongoc_client_pool_t:
823
824 mongoc_uri_t *uri = mongoc_uri_new (
825 "mongodb://hostA,hostB/?replicaSet=my_rs");
826
827 mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
828
829 When your program first calls mongoc_client_pool_pop, the pool launches
830 monitoring threads in the background. Monitoring threads independently
831 connect to all servers in the connection string. As monitoring threads
832 receive ismaster responses from the servers, they update the shared
833 view of the server topology. Additional monitoring threads and connec‐
834 tions are created as new servers are discovered. Monitoring threads are
835 terminated when servers are removed from the shared view of the server
836 topology.
837
838 Each thread that executes MongoDB operations must check out a client
839 from the pool:
840
841 mongoc_client_t *client = mongoc_client_pool_pop (pool);
842
843 /* use the client for operations ... */
844
845 mongoc_client_pool_push (pool, client);
846
847 The mongoc_client_t object is not thread-safe, only the mon‐
848 goc_client_pool_t is.
849
850 When the driver is in pooled mode, your program's operations are un‐
851 blocked as soon as monitoring discovers a usable server. For example,
852 if a thread in your program is waiting to execute an "insert" on the
853 primary, it is unblocked as soon as the primary is discovered, rather
854 than waiting for all secondaries to be checked as well.
855
856 The pool opens one connection per server for monitoring, and each
857 client opens its own connection to each server it uses for application
858 operations. Background monitoring threads re-scan servers independently
859 roughly every 10 seconds. This interval is configurable with heartbeat‐
860 FrequencyMS in the connection string. (See mongoc_uri_t.)
861
862 The connection string can also specify waitQueueTimeoutMS to limit the
863 time that mongoc_client_pool_pop will wait for a client from the pool.
864 (See mongoc_uri_t.) If waitQueueTimeoutMS is specified, then it is
865 necessary to confirm that a client was actually returned:
866
867 mongoc_uri_t *uri = mongoc_uri_new (
868 "mongodb://hostA,hostB/?replicaSet=my_rs&waitQueueTimeoutMS=1000");
869
870 mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
871
872 mongoc_client_t *client = mongoc_client_pool_pop (pool);
873
874 if (client) {
875 /* use the client for operations ... */
876
877 mongoc_client_pool_push (pool, client);
878 } else {
879 /* take appropriate action for a timeout */
880 }
881
882 See connection_pool_options to configure pool size and behavior, and
883 see mongoc_client_pool_t for an extended example of a multi-threaded
884 program that uses the driver in pooled mode.
885
887 Handling Cursor Failures
888 Cursors exist on a MongoDB server. However, the mongoc_cursor_t struc‐
889 ture gives the local process a handle to the cursor. It is possible for
890 errors to occur on the server while iterating a cursor on the client.
891 Even a network partition may occur. This means that applications should
892 be robust in handling cursor failures.
893
894 While iterating cursors, you should check to see if an error has oc‐
895 curred. See the following example for how to robustly check for errors.
896
897 static void
898 print_all_documents (mongoc_collection_t *collection)
899 {
900 mongoc_cursor_t *cursor;
901 const bson_t *doc;
902 bson_error_t error;
903 bson_t query = BSON_INITIALIZER;
904 char *str;
905
906 cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);
907
908 while (mongoc_cursor_next (cursor, &doc)) {
909 str = bson_as_canonical_extended_json (doc, NULL);
910 printf ("%s\n", str);
911 bson_free (str);
912 }
913
914 if (mongoc_cursor_error (cursor, &error)) {
915 fprintf (stderr, "Failed to iterate all documents: %s\n", error.message);
916 }
917
918 mongoc_cursor_destroy (cursor);
919 }
920
921 Destroying Server-Side Cursors
922 The MongoDB C driver will automatically destroy a server-side cursor
923 when mongoc_cursor_destroy() is called. Failure to call this function
924 when done with a cursor will leak memory client side as well as consume
925 extra memory server side. If the cursor was configured to never time‐
926 out, it will become a memory leak on the server.
927
928 Tailable Cursors
929 Tailable cursors are cursors that remain open even after they've re‐
930 turned a final result. This way, if more documents are added to a col‐
931 lection (i.e., to the cursor's result set), then you can continue to
932 call mongoc_cursor_next() to retrieve those additional results.
933
934 Here's a complete test case that demonstrates the use of tailable cur‐
935 sors.
936
937 NOTE:
938 Tailable cursors are for capped collections only.
939
940 An example to tail the oplog from a replica set.
941
942 mongoc-tail.c
943
944 #include <bson/bson.h>
945 #include <mongoc/mongoc.h>
946 #include <stdio.h>
947 #include <stdlib.h>
948
949 #ifdef _WIN32
950 #define sleep(_n) Sleep ((_n) *1000)
951 #endif
952
953
954 static void
955 print_bson (const bson_t *b)
956 {
957 char *str;
958
959 str = bson_as_canonical_extended_json (b, NULL);
960 fprintf (stdout, "%s\n", str);
961 bson_free (str);
962 }
963
964
965 static mongoc_cursor_t *
966 query_collection (mongoc_collection_t *collection, uint32_t last_time)
967 {
968 mongoc_cursor_t *cursor;
969 bson_t query;
970 bson_t gt;
971 bson_t opts;
972
973 BSON_ASSERT (collection);
974
975 bson_init (&query);
976 BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", >);
977 BSON_APPEND_TIMESTAMP (>, "$gt", last_time, 0);
978 bson_append_document_end (&query, >);
979
980 bson_init (&opts);
981 BSON_APPEND_BOOL (&opts, "tailable", true);
982 BSON_APPEND_BOOL (&opts, "awaitData", true);
983
984 cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL);
985
986 bson_destroy (&query);
987 bson_destroy (&opts);
988
989 return cursor;
990 }
991
992
993 static void
994 tail_collection (mongoc_collection_t *collection)
995 {
996 mongoc_cursor_t *cursor;
997 uint32_t last_time;
998 const bson_t *doc;
999 bson_error_t error;
1000 bson_iter_t iter;
1001
1002 BSON_ASSERT (collection);
1003
1004 last_time = (uint32_t) time (NULL);
1005
1006 while (true) {
1007 cursor = query_collection (collection, last_time);
1008 while (!mongoc_cursor_error (cursor, &error) &&
1009 mongoc_cursor_more (cursor)) {
1010 if (mongoc_cursor_next (cursor, &doc)) {
1011 if (bson_iter_init_find (&iter, doc, "ts") &&
1012 BSON_ITER_HOLDS_TIMESTAMP (&iter)) {
1013 bson_iter_timestamp (&iter, &last_time, NULL);
1014 }
1015 print_bson (doc);
1016 }
1017 }
1018 if (mongoc_cursor_error (cursor, &error)) {
1019 if (error.domain == MONGOC_ERROR_SERVER) {
1020 fprintf (stderr, "%s\n", error.message);
1021 exit (1);
1022 }
1023 }
1024
1025 mongoc_cursor_destroy (cursor);
1026 sleep (1);
1027 }
1028 }
1029
1030
1031 int
1032 main (int argc, char *argv[])
1033 {
1034 mongoc_collection_t *collection;
1035 mongoc_client_t *client;
1036 mongoc_uri_t *uri;
1037 bson_error_t error;
1038
1039 if (argc != 2) {
1040 fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]);
1041 return EXIT_FAILURE;
1042 }
1043
1044 mongoc_init ();
1045
1046 uri = mongoc_uri_new_with_error (argv[1], &error);
1047 if (!uri) {
1048 fprintf (stderr,
1049 "failed to parse URI: %s\n"
1050 "error message: %s\n",
1051 argv[1],
1052 error.message);
1053 return EXIT_FAILURE;
1054 }
1055
1056 client = mongoc_client_new_from_uri (uri);
1057 if (!client) {
1058 return EXIT_FAILURE;
1059 }
1060
1061 mongoc_client_set_error_api (client, 2);
1062
1063 collection = mongoc_client_get_collection (client, "local", "oplog.rs");
1064
1065 tail_collection (collection);
1066
1067 mongoc_collection_destroy (collection);
1068 mongoc_uri_destroy (uri);
1069 mongoc_client_destroy (client);
1070
1071 return EXIT_SUCCESS;
1072 }
1073
1074
1075 Let's compile and run this example against a replica set to see updates
1076 as they are made.
1077
1078 $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0)
1079 $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet
1080 {
1081 "h" : -8458503739429355503,
1082 "ns" : "test.test",
1083 "o" : {
1084 "_id" : {
1085 "$oid" : "5372ab0a25164be923d10d50"
1086 }
1087 },
1088 "op" : "i",
1089 "ts" : {
1090 "$timestamp" : {
1091 "i" : 1,
1092 "t" : 1400023818
1093 }
1094 },
1095 "v" : 2
1096 }
1097
1098 The line of output is a sample from performing db.test.insert({}) from
1099 the mongo shell on the replica set.
1100
1101 See also mongoc_cursor_set_max_await_time_ms.
1102
1104 This tutorial explains how to take advantage of MongoDB C driver bulk
1105 write operation features. Executing write operations in batches reduces
1106 the number of network round trips, increasing write throughput.
1107
1108 Bulk Insert
1109 First we need to fetch a bulk operation handle from the mongoc_collec‐
1110 tion_t.
1111
1112 mongoc_bulk_operation_t *bulk =
1113 mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1114
1115 We can now start inserting documents to the bulk operation. These will
1116 be buffered until we execute the operation.
1117
1118 The bulk operation will coalesce insertions as a single batch for each
1119 consecutive call to mongoc_bulk_operation_insert(). This creates a
1120 pipelined effect when possible.
1121
1122 To execute the bulk operation and receive the result we call mon‐
1123 goc_bulk_operation_execute().
1124
1125 bulk1.c
1126
1127 #include <assert.h>
1128 #include <mongoc/mongoc.h>
1129 #include <stdio.h>
1130
1131 static void
1132 bulk1 (mongoc_collection_t *collection)
1133 {
1134 mongoc_bulk_operation_t *bulk;
1135 bson_error_t error;
1136 bson_t *doc;
1137 bson_t reply;
1138 char *str;
1139 bool ret;
1140 int i;
1141
1142 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1143
1144 for (i = 0; i < 10000; i++) {
1145 doc = BCON_NEW ("i", BCON_INT32 (i));
1146 mongoc_bulk_operation_insert (bulk, doc);
1147 bson_destroy (doc);
1148 }
1149
1150 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1151
1152 str = bson_as_canonical_extended_json (&reply, NULL);
1153 printf ("%s\n", str);
1154 bson_free (str);
1155
1156 if (!ret) {
1157 fprintf (stderr, "Error: %s\n", error.message);
1158 }
1159
1160 bson_destroy (&reply);
1161 mongoc_bulk_operation_destroy (bulk);
1162 }
1163
1164 int
1165 main (int argc, char *argv[])
1166 {
1167 mongoc_client_t *client;
1168 mongoc_collection_t *collection;
1169 const char *uri_string = "mongodb://localhost/?appname=bulk1-example";
1170 mongoc_uri_t *uri;
1171 bson_error_t error;
1172
1173 mongoc_init ();
1174
1175 uri = mongoc_uri_new_with_error (uri_string, &error);
1176 if (!uri) {
1177 fprintf (stderr,
1178 "failed to parse URI: %s\n"
1179 "error message: %s\n",
1180 uri_string,
1181 error.message);
1182 return EXIT_FAILURE;
1183 }
1184
1185 client = mongoc_client_new_from_uri (uri);
1186 if (!client) {
1187 return EXIT_FAILURE;
1188 }
1189
1190 mongoc_client_set_error_api (client, 2);
1191 collection = mongoc_client_get_collection (client, "test", "test");
1192
1193 bulk1 (collection);
1194
1195 mongoc_uri_destroy (uri);
1196 mongoc_collection_destroy (collection);
1197 mongoc_client_destroy (client);
1198
1199 mongoc_cleanup ();
1200
1201 return EXIT_SUCCESS;
1202 }
1203
1204
1205 Example reply document:
1206
1207 {"nInserted" : 10000,
1208 "nMatched" : 0,
1209 "nModified" : 0,
1210 "nRemoved" : 0,
1211 "nUpserted" : 0,
1212 "writeErrors" : []
1213 "writeConcernErrors" : [] }
1214
1215 Mixed Bulk Write Operations
1216 MongoDB C driver also supports executing mixed bulk write operations. A
1217 batch of insert, update, and remove operations can be executed together
1218 using the bulk write operations API.
1219
1220 Ordered Bulk Write Operations
1221 Ordered bulk write operations are batched and sent to the server in the
1222 order provided for serial execution. The reply document describes the
1223 type and count of operations performed.
1224
1225 bulk2.c
1226
1227 #include <assert.h>
1228 #include <mongoc/mongoc.h>
1229 #include <stdio.h>
1230
1231 static void
1232 bulk2 (mongoc_collection_t *collection)
1233 {
1234 mongoc_bulk_operation_t *bulk;
1235 bson_error_t error;
1236 bson_t *query;
1237 bson_t *doc;
1238 bson_t *opts;
1239 bson_t reply;
1240 char *str;
1241 bool ret;
1242 int i;
1243
1244 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1245
1246 /* Remove everything */
1247 query = bson_new ();
1248 mongoc_bulk_operation_remove (bulk, query);
1249 bson_destroy (query);
1250
1251 /* Add a few documents */
1252 for (i = 1; i < 4; i++) {
1253 doc = BCON_NEW ("_id", BCON_INT32 (i));
1254 mongoc_bulk_operation_insert (bulk, doc);
1255 bson_destroy (doc);
1256 }
1257
1258 /* {_id: 1} => {$set: {foo: "bar"}} */
1259 query = BCON_NEW ("_id", BCON_INT32 (1));
1260 doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}");
1261 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, NULL, &error);
1262 bson_destroy (query);
1263 bson_destroy (doc);
1264
1265 /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */
1266 opts = BCON_NEW ("upsert", BCON_BOOL (true));
1267 query = BCON_NEW ("_id", BCON_INT32 (4));
1268 doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}");
1269 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, opts, &error);
1270 bson_destroy (query);
1271 bson_destroy (doc);
1272 bson_destroy (opts);
1273
1274 /* replace {j:1} with {j:2} */
1275 query = BCON_NEW ("j", BCON_INT32 (1));
1276 doc = BCON_NEW ("j", BCON_INT32 (2));
1277 mongoc_bulk_operation_replace_one_with_opts (bulk, query, doc, NULL, &error);
1278 bson_destroy (query);
1279 bson_destroy (doc);
1280
1281 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1282
1283 str = bson_as_canonical_extended_json (&reply, NULL);
1284 printf ("%s\n", str);
1285 bson_free (str);
1286
1287 if (!ret) {
1288 printf ("Error: %s\n", error.message);
1289 }
1290
1291 bson_destroy (&reply);
1292 mongoc_bulk_operation_destroy (bulk);
1293 }
1294
1295 int
1296 main (int argc, char *argv[])
1297 {
1298 mongoc_client_t *client;
1299 mongoc_collection_t *collection;
1300 const char *uri_string = "mongodb://localhost/?appname=bulk2-example";
1301 mongoc_uri_t *uri;
1302 bson_error_t error;
1303
1304 mongoc_init ();
1305
1306 uri = mongoc_uri_new_with_error (uri_string, &error);
1307 if (!uri) {
1308 fprintf (stderr,
1309 "failed to parse URI: %s\n"
1310 "error message: %s\n",
1311 uri_string,
1312 error.message);
1313 return EXIT_FAILURE;
1314 }
1315
1316 client = mongoc_client_new_from_uri (uri);
1317 if (!client) {
1318 return EXIT_FAILURE;
1319 }
1320
1321 mongoc_client_set_error_api (client, 2);
1322 collection = mongoc_client_get_collection (client, "test", "test");
1323
1324 bulk2 (collection);
1325
1326 mongoc_uri_destroy (uri);
1327 mongoc_collection_destroy (collection);
1328 mongoc_client_destroy (client);
1329
1330 mongoc_cleanup ();
1331
1332 return EXIT_SUCCESS;
1333 }
1334
1335
1336 Example reply document:
1337
1338 { "nInserted" : 3,
1339 "nMatched" : 2,
1340 "nModified" : 2,
1341 "nRemoved" : 10000,
1342 "nUpserted" : 1,
1343 "upserted" : [{"index" : 5, "_id" : 4}],
1344 "writeErrors" : []
1345 "writeConcernErrors" : [] }
1346
1347 The index field in the upserted array is the 0-based index of the up‐
1348 sert operation; in this example, the sixth operation of the overall
1349 bulk operation was an upsert, so its index is 5.
1350
1351 Unordered Bulk Write Operations
1352 Unordered bulk write operations are batched and sent to the server in
1353 arbitrary order where they may be executed in parallel. Any errors that
1354 occur are reported after all operations are attempted.
1355
1356 In the next example the first and third operations fail due to the
1357 unique constraint on _id. Since we are doing unordered execution the
1358 second and fourth operations succeed.
1359
1360 bulk3.c
1361
1362 #include <assert.h>
1363 #include <mongoc/mongoc.h>
1364 #include <stdio.h>
1365
1366 static void
1367 bulk3 (mongoc_collection_t *collection)
1368 {
1369 bson_t opts = BSON_INITIALIZER;
1370 mongoc_bulk_operation_t *bulk;
1371 bson_error_t error;
1372 bson_t *query;
1373 bson_t *doc;
1374 bson_t reply;
1375 char *str;
1376 bool ret;
1377
1378 /* false indicates unordered */
1379 BSON_APPEND_BOOL (&opts, "ordered", false);
1380 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1381 bson_destroy (&opts);
1382
1383 /* Add a document */
1384 doc = BCON_NEW ("_id", BCON_INT32 (1));
1385 mongoc_bulk_operation_insert (bulk, doc);
1386 bson_destroy (doc);
1387
1388 /* remove {_id: 2} */
1389 query = BCON_NEW ("_id", BCON_INT32 (2));
1390 mongoc_bulk_operation_remove_one (bulk, query);
1391 bson_destroy (query);
1392
1393 /* insert {_id: 3} */
1394 doc = BCON_NEW ("_id", BCON_INT32 (3));
1395 mongoc_bulk_operation_insert (bulk, doc);
1396 bson_destroy (doc);
1397
1398 /* replace {_id:4} {'i': 1} */
1399 query = BCON_NEW ("_id", BCON_INT32 (4));
1400 doc = BCON_NEW ("i", BCON_INT32 (1));
1401 mongoc_bulk_operation_replace_one (bulk, query, doc, false);
1402 bson_destroy (query);
1403 bson_destroy (doc);
1404
1405 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1406
1407 str = bson_as_canonical_extended_json (&reply, NULL);
1408 printf ("%s\n", str);
1409 bson_free (str);
1410
1411 if (!ret) {
1412 printf ("Error: %s\n", error.message);
1413 }
1414
1415 bson_destroy (&reply);
1416 mongoc_bulk_operation_destroy (bulk);
1417 bson_destroy (&opts);
1418 }
1419
1420 int
1421 main (int argc, char *argv[])
1422 {
1423 mongoc_client_t *client;
1424 mongoc_collection_t *collection;
1425 const char *uri_string = "mongodb://localhost/?appname=bulk3-example";
1426 mongoc_uri_t *uri;
1427 bson_error_t error;
1428
1429 mongoc_init ();
1430
1431 uri = mongoc_uri_new_with_error (uri_string, &error);
1432 if (!uri) {
1433 fprintf (stderr,
1434 "failed to parse URI: %s\n"
1435 "error message: %s\n",
1436 uri_string,
1437 error.message);
1438 return EXIT_FAILURE;
1439 }
1440
1441 client = mongoc_client_new_from_uri (uri);
1442 if (!client) {
1443 return EXIT_FAILURE;
1444 }
1445
1446 mongoc_client_set_error_api (client, 2);
1447 collection = mongoc_client_get_collection (client, "test", "test");
1448
1449 bulk3 (collection);
1450
1451 mongoc_uri_destroy (uri);
1452 mongoc_collection_destroy (collection);
1453 mongoc_client_destroy (client);
1454
1455 mongoc_cleanup ();
1456
1457 return EXIT_SUCCESS;
1458 }
1459
1460
1461 Example reply document:
1462
1463 { "nInserted" : 0,
1464 "nMatched" : 1,
1465 "nModified" : 1,
1466 "nRemoved" : 1,
1467 "nUpserted" : 0,
1468 "writeErrors" : [
1469 { "index" : 0,
1470 "code" : 11000,
1471 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" },
1472 { "index" : 2,
1473 "code" : 11000,
1474 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ],
1475 "writeConcernErrors" : [] }
1476
1477 Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }
1478
1479 The bson_error_t domain is MONGOC_ERROR_COMMAND and its code is 11000.
1480
1481 Bulk Operation Bypassing Document Validation
1482 This feature is only available when using MongoDB 3.2 and later.
1483
1484 By default bulk operations are validated against the schema, if any is
1485 defined. In certain cases however it may be necessary to bypass the
1486 document validation.
1487
1488 bulk5.c
1489
1490 #include <assert.h>
1491 #include <mongoc/mongoc.h>
1492 #include <stdio.h>
1493
1494 static void
1495 bulk5_fail (mongoc_collection_t *collection)
1496 {
1497 mongoc_bulk_operation_t *bulk;
1498 bson_error_t error;
1499 bson_t *doc;
1500 bson_t reply;
1501 char *str;
1502 bool ret;
1503
1504 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1505
1506 /* Two inserts */
1507 doc = BCON_NEW ("_id", BCON_INT32 (31));
1508 mongoc_bulk_operation_insert (bulk, doc);
1509 bson_destroy (doc);
1510
1511 doc = BCON_NEW ("_id", BCON_INT32 (32));
1512 mongoc_bulk_operation_insert (bulk, doc);
1513 bson_destroy (doc);
1514
1515 /* The above documents do not comply to the schema validation rules
1516 * we created previously, so this will result in an error */
1517 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1518
1519 str = bson_as_canonical_extended_json (&reply, NULL);
1520 printf ("%s\n", str);
1521 bson_free (str);
1522
1523 if (!ret) {
1524 printf ("Error: %s\n", error.message);
1525 }
1526
1527 bson_destroy (&reply);
1528 mongoc_bulk_operation_destroy (bulk);
1529 }
1530
1531 static void
1532 bulk5_success (mongoc_collection_t *collection)
1533 {
1534 mongoc_bulk_operation_t *bulk;
1535 bson_error_t error;
1536 bson_t *doc;
1537 bson_t reply;
1538 char *str;
1539 bool ret;
1540
1541 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1542
1543 /* Allow this document to bypass document validation.
1544 * NOTE: When authentication is enabled, the authenticated user must have
1545 * either the "dbadmin" or "restore" roles to bypass document validation */
1546 mongoc_bulk_operation_set_bypass_document_validation (bulk, true);
1547
1548 /* Two inserts */
1549 doc = BCON_NEW ("_id", BCON_INT32 (31));
1550 mongoc_bulk_operation_insert (bulk, doc);
1551 bson_destroy (doc);
1552
1553 doc = BCON_NEW ("_id", BCON_INT32 (32));
1554 mongoc_bulk_operation_insert (bulk, doc);
1555 bson_destroy (doc);
1556
1557 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1558
1559 str = bson_as_canonical_extended_json (&reply, NULL);
1560 printf ("%s\n", str);
1561 bson_free (str);
1562
1563 if (!ret) {
1564 printf ("Error: %s\n", error.message);
1565 }
1566
1567 bson_destroy (&reply);
1568 mongoc_bulk_operation_destroy (bulk);
1569 }
1570
1571 int
1572 main (int argc, char *argv[])
1573 {
1574 bson_t *options;
1575 bson_error_t error;
1576 mongoc_client_t *client;
1577 mongoc_collection_t *collection;
1578 mongoc_database_t *database;
1579 const char *uri_string = "mongodb://localhost/?appname=bulk5-example";
1580 mongoc_uri_t *uri;
1581
1582 mongoc_init ();
1583
1584 uri = mongoc_uri_new_with_error (uri_string, &error);
1585 if (!uri) {
1586 fprintf (stderr,
1587 "failed to parse URI: %s\n"
1588 "error message: %s\n",
1589 uri_string,
1590 error.message);
1591 return EXIT_FAILURE;
1592 }
1593
1594 client = mongoc_client_new_from_uri (uri);
1595 if (!client) {
1596 return EXIT_FAILURE;
1597 }
1598
1599 mongoc_client_set_error_api (client, 2);
1600 database = mongoc_client_get_database (client, "testasdf");
1601
1602 /* Create schema validator */
1603 options = BCON_NEW (
1604 "validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}");
1605 collection =
1606 mongoc_database_create_collection (database, "collname", options, &error);
1607
1608 if (collection) {
1609 bulk5_fail (collection);
1610 bulk5_success (collection);
1611 mongoc_collection_destroy (collection);
1612 } else {
1613 fprintf (stderr, "Couldn't create collection: '%s'\n", error.message);
1614 }
1615
1616 bson_free (options);
1617 mongoc_uri_destroy (uri);
1618 mongoc_database_destroy (database);
1619 mongoc_client_destroy (client);
1620
1621 mongoc_cleanup ();
1622
1623 return EXIT_SUCCESS;
1624 }
1625
1626
1627 Running the above example will result in:
1628
1629 { "nInserted" : 0,
1630 "nMatched" : 0,
1631 "nModified" : 0,
1632 "nRemoved" : 0,
1633 "nUpserted" : 0,
1634 "writeErrors" : [
1635 { "index" : 0,
1636 "code" : 121,
1637 "errmsg" : "Document failed validation" } ] }
1638
1639 Error: Document failed validation
1640
1641 { "nInserted" : 2,
1642 "nMatched" : 0,
1643 "nModified" : 0,
1644 "nRemoved" : 0,
1645 "nUpserted" : 0,
1646 "writeErrors" : [] }
1647
1648 The bson_error_t domain is MONGOC_ERROR_COMMAND.
1649
1650 Bulk Operation Write Concerns
1651 By default bulk operations are executed with the write_concern of the
1652 collection they are executed against. A custom write concern can be
1653 passed to the mongoc_collection_create_bulk_operation_with_opts()
1654 method. Write concern errors (e.g. wtimeout) will be reported after all
1655 operations are attempted, regardless of execution order.
1656
1657 bulk4.c
1658
1659 #include <assert.h>
1660 #include <mongoc/mongoc.h>
1661 #include <stdio.h>
1662
1663 static void
1664 bulk4 (mongoc_collection_t *collection)
1665 {
1666 bson_t opts = BSON_INITIALIZER;
1667 mongoc_write_concern_t *wc;
1668 mongoc_bulk_operation_t *bulk;
1669 bson_error_t error;
1670 bson_t *doc;
1671 bson_t reply;
1672 char *str;
1673 bool ret;
1674
1675 wc = mongoc_write_concern_new ();
1676 mongoc_write_concern_set_w (wc, 4);
1677 mongoc_write_concern_set_wtimeout_int64 (wc, 100); /* milliseconds */
1678 mongoc_write_concern_append (wc, &opts);
1679
1680 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1681
1682 /* Two inserts */
1683 doc = BCON_NEW ("_id", BCON_INT32 (10));
1684 mongoc_bulk_operation_insert (bulk, doc);
1685 bson_destroy (doc);
1686
1687 doc = BCON_NEW ("_id", BCON_INT32 (11));
1688 mongoc_bulk_operation_insert (bulk, doc);
1689 bson_destroy (doc);
1690
1691 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1692
1693 str = bson_as_canonical_extended_json (&reply, NULL);
1694 printf ("%s\n", str);
1695 bson_free (str);
1696
1697 if (!ret) {
1698 printf ("Error: %s\n", error.message);
1699 }
1700
1701 bson_destroy (&reply);
1702 mongoc_bulk_operation_destroy (bulk);
1703 mongoc_write_concern_destroy (wc);
1704 bson_destroy (&opts);
1705 }
1706
1707 int
1708 main (int argc, char *argv[])
1709 {
1710 mongoc_client_t *client;
1711 mongoc_collection_t *collection;
1712 const char *uri_string = "mongodb://localhost/?appname=bulk4-example";
1713 mongoc_uri_t *uri;
1714 bson_error_t error;
1715
1716 mongoc_init ();
1717
1718 uri = mongoc_uri_new_with_error (uri_string, &error);
1719 if (!uri) {
1720 fprintf (stderr,
1721 "failed to parse URI: %s\n"
1722 "error message: %s\n",
1723 uri_string,
1724 error.message);
1725 return EXIT_FAILURE;
1726 }
1727
1728 client = mongoc_client_new_from_uri (uri);
1729 if (!client) {
1730 return EXIT_FAILURE;
1731 }
1732
1733 mongoc_client_set_error_api (client, 2);
1734 collection = mongoc_client_get_collection (client, "test", "test");
1735
1736 bulk4 (collection);
1737
1738 mongoc_uri_destroy (uri);
1739 mongoc_collection_destroy (collection);
1740 mongoc_client_destroy (client);
1741
1742 mongoc_cleanup ();
1743
1744 return EXIT_SUCCESS;
1745 }
1746
1747
1748 Example reply document and error message:
1749
1750 { "nInserted" : 2,
1751 "nMatched" : 0,
1752 "nModified" : 0,
1753 "nRemoved" : 0,
1754 "nUpserted" : 0,
1755 "writeErrors" : [],
1756 "writeConcernErrors" : [
1757 { "code" : 64,
1758 "errmsg" : "waiting for replication timed out" }
1759 ] }
1760
1761 Error: waiting for replication timed out
1762
1763 The bson_error_t domain is MONGOC_ERROR_WRITE_CONCERN if there are
1764 write concern errors and no write errors. Write errors indicate failed
1765 operations, so they take precedence over write concern errors, which
1766 mean merely that the write concern is not satisfied yet.
1767
1768 Setting Collation Order
1769 This feature is only available when using MongoDB 3.4 and later.
1770
1771 bulk-collation.c
1772
1773 #include <mongoc/mongoc.h>
1774 #include <stdio.h>
1775
1776 static void
1777 bulk_collation (mongoc_collection_t *collection)
1778 {
1779 mongoc_bulk_operation_t *bulk;
1780 bson_t *opts;
1781 bson_t *doc;
1782 bson_t *selector;
1783 bson_t *update;
1784 bson_error_t error;
1785 bson_t reply;
1786 char *str;
1787 uint32_t ret;
1788
1789 /* insert {_id: "one"} and {_id: "One"} */
1790 bulk = mongoc_collection_create_bulk_operation_with_opts (
1791 collection, NULL);
1792 doc = BCON_NEW ("_id", BCON_UTF8 ("one"));
1793 mongoc_bulk_operation_insert (bulk, doc);
1794 bson_destroy (doc);
1795
1796 doc = BCON_NEW ("_id", BCON_UTF8 ("One"));
1797 mongoc_bulk_operation_insert (bulk, doc);
1798 bson_destroy (doc);
1799
1800 /* "One" normally sorts before "one"; make "one" come first */
1801 opts = BCON_NEW ("collation",
1802 "{",
1803 "locale",
1804 BCON_UTF8 ("en_US"),
1805 "caseFirst",
1806 BCON_UTF8 ("lower"),
1807 "}");
1808
1809 /* set x=1 on the document with _id "One", which now sorts after "one" */
1810 update = BCON_NEW ("$set", "{", "x", BCON_INT64 (1), "}");
1811 selector = BCON_NEW ("_id", "{", "$gt", BCON_UTF8 ("one"), "}");
1812 mongoc_bulk_operation_update_one_with_opts (
1813 bulk, selector, update, opts, &error);
1814
1815 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1816
1817 str = bson_as_canonical_extended_json (&reply, NULL);
1818 printf ("%s\n", str);
1819 bson_free (str);
1820
1821 if (!ret) {
1822 printf ("Error: %s\n", error.message);
1823 }
1824
1825 bson_destroy (&reply);
1826 bson_destroy (update);
1827 bson_destroy (selector);
1828 bson_destroy (opts);
1829 mongoc_bulk_operation_destroy (bulk);
1830 }
1831
1832 int
1833 main (int argc, char *argv[])
1834 {
1835 mongoc_client_t *client;
1836 mongoc_collection_t *collection;
1837 const char *uri_string = "mongodb://localhost/?appname=bulk-collation";
1838 mongoc_uri_t *uri;
1839 bson_error_t error;
1840
1841 mongoc_init ();
1842
1843 uri = mongoc_uri_new_with_error (uri_string, &error);
1844 if (!uri) {
1845 fprintf (stderr,
1846 "failed to parse URI: %s\n"
1847 "error message: %s\n",
1848 uri_string,
1849 error.message);
1850 return EXIT_FAILURE;
1851 }
1852
1853 client = mongoc_client_new_from_uri (uri);
1854 if (!client) {
1855 return EXIT_FAILURE;
1856 }
1857
1858 mongoc_client_set_error_api (client, 2);
1859 collection = mongoc_client_get_collection (client, "db", "collection");
1860 bulk_collation (collection);
1861
1862 mongoc_uri_destroy (uri);
1863 mongoc_collection_destroy (collection);
1864 mongoc_client_destroy (client);
1865
1866 mongoc_cleanup ();
1867
1868 return EXIT_SUCCESS;
1869 }
1870
1871
1872 Running the above example will result in:
1873
1874 { "nInserted" : 2,
1875 "nMatched" : 1,
1876 "nModified" : 1,
1877 "nRemoved" : 0,
1878 "nUpserted" : 0,
1879 "writeErrors" : [ ]
1880 }
1881
1882 Unacknowledged Bulk Writes
1883 Set "w" to zero for an unacknowledged write. The driver sends unac‐
1884 knowledged writes using the legacy opcodes OP_INSERT, OP_UPDATE, and
1885 OP_DELETE.
1886
1887 bulk6.c
1888
1889 #include <mongoc/mongoc.h>
1890 #include <stdio.h>
1891
1892 static void
1893 bulk6 (mongoc_collection_t *collection)
1894 {
1895 bson_t opts = BSON_INITIALIZER;
1896 mongoc_write_concern_t *wc;
1897 mongoc_bulk_operation_t *bulk;
1898 bson_error_t error;
1899 bson_t *doc;
1900 bson_t *selector;
1901 bson_t reply;
1902 char *str;
1903 bool ret;
1904
1905 wc = mongoc_write_concern_new ();
1906 mongoc_write_concern_set_w (wc, 0);
1907 mongoc_write_concern_append (wc, &opts);
1908
1909 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1910
1911 doc = BCON_NEW ("_id", BCON_INT32 (10));
1912 mongoc_bulk_operation_insert (bulk, doc);
1913 bson_destroy (doc);
1914
1915 selector = BCON_NEW ("_id", BCON_INT32 (11));
1916 mongoc_bulk_operation_remove_one (bulk, selector);
1917 bson_destroy (selector);
1918
1919 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1920
1921 str = bson_as_canonical_extended_json (&reply, NULL);
1922 printf ("%s\n", str);
1923 bson_free (str);
1924
1925 if (!ret) {
1926 printf ("Error: %s\n", error.message);
1927 }
1928
1929 bson_destroy (&reply);
1930 mongoc_bulk_operation_destroy (bulk);
1931 mongoc_write_concern_destroy (wc);
1932 bson_destroy (&opts);
1933 }
1934
1935 int
1936 main (int argc, char *argv[])
1937 {
1938 mongoc_client_t *client;
1939 mongoc_collection_t *collection;
1940 const char *uri_string = "mongodb://localhost/?appname=bulk6-example";
1941 mongoc_uri_t *uri;
1942 bson_error_t error;
1943
1944 mongoc_init ();
1945
1946 uri = mongoc_uri_new_with_error (uri_string, &error);
1947 if (!uri) {
1948 fprintf (stderr,
1949 "failed to parse URI: %s\n"
1950 "error message: %s\n",
1951 uri_string,
1952 error.message);
1953 return EXIT_FAILURE;
1954 }
1955
1956 client = mongoc_client_new_from_uri (uri);
1957 if (!client) {
1958 return EXIT_FAILURE;
1959 }
1960
1961 mongoc_client_set_error_api (client, 2);
1962 collection = mongoc_client_get_collection (client, "test", "test");
1963
1964 bulk6 (collection);
1965
1966 mongoc_uri_destroy (uri);
1967 mongoc_collection_destroy (collection);
1968 mongoc_client_destroy (client);
1969
1970 mongoc_cleanup ();
1971
1972 return EXIT_SUCCESS;
1973 }
1974
1975
1976 The reply document is empty:
1977
1978 { }
1979
1980 Further Reading
1981 See the Driver Bulk API Spec, which describes bulk write operations for
1982 all MongoDB drivers.
1983
1985 This document provides a number of practical examples that display the
1986 capabilities of the aggregation framework.
1987
1988 The Aggregations using the Zip Codes Data Set examples uses a publicly
1989 available data set of all zipcodes and populations in the United
1990 States. These data are available at: zips.json.
1991
1992 Requirements
1993 Let's check if everything is installed.
1994
1995 Use the following command to load zips.json data set into mongod in‐
1996 stance:
1997
1998 $ mongoimport --drop -d test -c zipcodes zips.json
1999
2000 Let's use the MongoDB shell to verify that everything was imported suc‐
2001 cessfully.
2002
2003 $ mongo test
2004 connecting to: test
2005 > db.zipcodes.count()
2006 29467
2007 > db.zipcodes.findOne()
2008 {
2009 "_id" : "35004",
2010 "city" : "ACMAR",
2011 "loc" : [
2012 -86.51557,
2013 33.584132
2014 ],
2015 "pop" : 6055,
2016 "state" : "AL"
2017 }
2018
2019 Aggregations using the Zip Codes Data Set
2020 Each document in this collection has the following form:
2021
2022 {
2023 "_id" : "35004",
2024 "city" : "Acmar",
2025 "state" : "AL",
2026 "pop" : 6055,
2027 "loc" : [-86.51557, 33.584132]
2028 }
2029
2030 In these documents:
2031
2032 • The _id field holds the zipcode as a string.
2033
2034 • The city field holds the city name.
2035
2036 • The state field holds the two letter state abbreviation.
2037
2038 • The pop field holds the population.
2039
2040 • The loc field holds the location as a [latitude, longitude] array.
2041
2042 States with Populations Over 10 Million
2043 To get all states with a population greater than 10 million, use the
2044 following aggregation pipeline:
2045
2046 aggregation1.c
2047
2048 #include <mongoc/mongoc.h>
2049 #include <stdio.h>
2050
2051 static void
2052 print_pipeline (mongoc_collection_t *collection)
2053 {
2054 mongoc_cursor_t *cursor;
2055 bson_error_t error;
2056 const bson_t *doc;
2057 bson_t *pipeline;
2058 char *str;
2059
2060 pipeline = BCON_NEW ("pipeline",
2061 "[",
2062 "{",
2063 "$group",
2064 "{",
2065 "_id",
2066 "$state",
2067 "total_pop",
2068 "{",
2069 "$sum",
2070 "$pop",
2071 "}",
2072 "}",
2073 "}",
2074 "{",
2075 "$match",
2076 "{",
2077 "total_pop",
2078 "{",
2079 "$gte",
2080 BCON_INT32 (10000000),
2081 "}",
2082 "}",
2083 "}",
2084 "]");
2085
2086 cursor = mongoc_collection_aggregate (
2087 collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL);
2088
2089 while (mongoc_cursor_next (cursor, &doc)) {
2090 str = bson_as_canonical_extended_json (doc, NULL);
2091 printf ("%s\n", str);
2092 bson_free (str);
2093 }
2094
2095 if (mongoc_cursor_error (cursor, &error)) {
2096 fprintf (stderr, "Cursor Failure: %s\n", error.message);
2097 }
2098
2099 mongoc_cursor_destroy (cursor);
2100 bson_destroy (pipeline);
2101 }
2102
2103 int
2104 main (int argc, char *argv[])
2105 {
2106 mongoc_client_t *client;
2107 mongoc_collection_t *collection;
2108 const char *uri_string =
2109 "mongodb://localhost:27017/?appname=aggregation-example";
2110 mongoc_uri_t *uri;
2111 bson_error_t error;
2112
2113 mongoc_init ();
2114
2115 uri = mongoc_uri_new_with_error (uri_string, &error);
2116 if (!uri) {
2117 fprintf (stderr,
2118 "failed to parse URI: %s\n"
2119 "error message: %s\n",
2120 uri_string,
2121 error.message);
2122 return EXIT_FAILURE;
2123 }
2124
2125 client = mongoc_client_new_from_uri (uri);
2126 if (!client) {
2127 return EXIT_FAILURE;
2128 }
2129
2130 mongoc_client_set_error_api (client, 2);
2131 collection = mongoc_client_get_collection (client, "test", "zipcodes");
2132
2133 print_pipeline (collection);
2134
2135 mongoc_uri_destroy (uri);
2136 mongoc_collection_destroy (collection);
2137 mongoc_client_destroy (client);
2138
2139 mongoc_cleanup ();
2140
2141 return EXIT_SUCCESS;
2142 }
2143
2144
2145 You should see a result like the following:
2146
2147 { "_id" : "PA", "total_pop" : 11881643 }
2148 { "_id" : "OH", "total_pop" : 10847115 }
2149 { "_id" : "NY", "total_pop" : 17990455 }
2150 { "_id" : "FL", "total_pop" : 12937284 }
2151 { "_id" : "TX", "total_pop" : 16986510 }
2152 { "_id" : "IL", "total_pop" : 11430472 }
2153 { "_id" : "CA", "total_pop" : 29760021 }
2154
2155 The above aggregation pipeline is build from two pipeline operators:
2156 $group and $match.
2157
2158 The $group pipeline operator requires _id field where we specify group‐
2159 ing; remaining fields specify how to generate composite value and must
2160 use one of the group aggregation functions: $addToSet, $first, $last,
2161 $max, $min, $avg, $push, $sum. The $match pipeline operator syntax is
2162 the same as the read operation query syntax.
2163
2164 The $group process reads all documents and for each state it creates a
2165 separate document, for example:
2166
2167 { "_id" : "WA", "total_pop" : 4866692 }
2168
2169 The total_pop field uses the $sum aggregation function to sum the val‐
2170 ues of all pop fields in the source documents.
2171
2172 Documents created by $group are piped to the $match pipeline operator.
2173 It returns the documents with the value of total_pop field greater than
2174 or equal to 10 million.
2175
2176 Average City Population by State
2177 To get the first three states with the greatest average population per
2178 city, use the following aggregation:
2179
2180 pipeline = BCON_NEW ("pipeline", "[",
2181 "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}",
2182 "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}",
2183 "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}",
2184 "{", "$limit", BCON_INT32 (3) "}",
2185 "]");
2186
2187 This aggregate pipeline produces:
2188
2189 { "_id" : "DC", "avg_city_pop" : 303450.0 }
2190 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2191 { "_id" : "CA", "avg_city_pop" : 27735.341099720412 }
2192
2193 The above aggregation pipeline is build from three pipeline operators:
2194 $group, $sort and $limit.
2195
2196 The first $group operator creates the following documents:
2197
2198 { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 }
2199
2200 Note, that the $group operator can't use nested documents except the
2201 _id field.
2202
2203 The second $group uses these documents to create the following docu‐
2204 ments:
2205
2206 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2207
2208 These documents are sorted by the avg_city_pop field in descending or‐
2209 der. Finally, the $limit pipeline operator returns the first 3 docu‐
2210 ments from the sorted set.
2211
2213 This document provides some practical, simple, examples to demonstrate
2214 the distinct and mapReduce commands.
2215
2216 Setup
2217 First we'll write some code to insert sample data:
2218
2219 doc-common-insert.c
2220
2221 /* Don't try to compile this file on its own. It's meant to be #included
2222 by example code */
2223
2224 /* Insert some sample data */
2225 bool
2226 insert_data (mongoc_collection_t *collection)
2227 {
2228 mongoc_bulk_operation_t *bulk;
2229 enum N { ndocs = 4 };
2230 bson_t *docs[ndocs];
2231 bson_error_t error;
2232 int i = 0;
2233 bool ret;
2234
2235 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
2236
2237 docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
2238 docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
2239 docs[2] = BCON_NEW (
2240 "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
2241 docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
2242
2243 for (i = 0; i < ndocs; i++) {
2244 mongoc_bulk_operation_insert (bulk, docs[i]);
2245 bson_destroy (docs[i]);
2246 docs[i] = NULL;
2247 }
2248
2249 ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
2250
2251 if (!ret) {
2252 fprintf (stderr, "Error inserting data: %s\n", error.message);
2253 }
2254
2255 mongoc_bulk_operation_destroy (bulk);
2256 return ret;
2257 }
2258
2259 /* A helper which we'll use a lot later on */
2260 void
2261 print_res (const bson_t *reply)
2262 {
2263 char *str;
2264 BSON_ASSERT (reply);
2265 str = bson_as_canonical_extended_json (reply, NULL);
2266 printf ("%s\n", str);
2267 bson_free (str);
2268 }
2269
2270
2271 distinct command
2272 This is how to use the distinct command to get the distinct values of x
2273 which are greater than 1:
2274
2275 distinct.c
2276
2277 bool
2278 distinct (mongoc_database_t *database)
2279 {
2280 bson_t *command;
2281 bson_t reply;
2282 bson_error_t error;
2283 bool res;
2284 bson_iter_t iter;
2285 bson_iter_t array_iter;
2286 double val;
2287
2288 command = BCON_NEW ("distinct",
2289 BCON_UTF8 (COLLECTION_NAME),
2290 "key",
2291 BCON_UTF8 ("x"),
2292 "query",
2293 "{",
2294 "x",
2295 "{",
2296 "$gt",
2297 BCON_DOUBLE (1.0),
2298 "}",
2299 "}");
2300 res =
2301 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2302 if (!res) {
2303 fprintf (stderr, "Error with distinct: %s\n", error.message);
2304 goto cleanup;
2305 }
2306
2307 /* Do something with reply (in this case iterate through the values) */
2308 if (!(bson_iter_init_find (&iter, &reply, "values") &&
2309 BSON_ITER_HOLDS_ARRAY (&iter) &&
2310 bson_iter_recurse (&iter, &array_iter))) {
2311 fprintf (stderr, "Couldn't extract \"values\" field from response\n");
2312 goto cleanup;
2313 }
2314
2315 while (bson_iter_next (&array_iter)) {
2316 if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) {
2317 val = bson_iter_double (&array_iter);
2318 printf ("Next double: %f\n", val);
2319 }
2320 }
2321
2322 cleanup:
2323 /* cleanup */
2324 bson_destroy (command);
2325 bson_destroy (&reply);
2326 return res;
2327 }
2328
2329
2330 mapReduce - basic example
2331 A simple example using the map reduce framework. It simply adds up the
2332 number of occurrences of each "tag".
2333
2334 First define the map and reduce functions:
2335
2336 constants.c
2337
2338 const char *const COLLECTION_NAME = "things";
2339
2340 /* Our map function just emits a single (key, 1) pair for each tag
2341 in the array: */
2342 const char *const MAPPER = "function () {"
2343 "this.tags.forEach(function(z) {"
2344 "emit(z, 1);"
2345 "});"
2346 "}";
2347
2348 /* The reduce function sums over all of the emitted values for a
2349 given key: */
2350 const char *const REDUCER = "function (key, values) {"
2351 "var total = 0;"
2352 "for (var i = 0; i < values.length; i++) {"
2353 "total += values[i];"
2354 "}"
2355 "return total;"
2356 "}";
2357 /* Note We can't just return values.length as the reduce function
2358 might be called iteratively on the results of other reduce
2359 steps. */
2360
2361
2362 Run the mapReduce command. Use the generic command helpers (e.g. mon‐
2363 goc_database_command_simple()). Do not the read command helpers (e.g.
2364 mongoc_database_read_command_with_opts()) because they are considered
2365 retryable read operations. If retryable reads are enabled, those opera‐
2366 tions will retry once on a retryable error, giving undesirable behavior
2367 for mapReduce.
2368
2369 map-reduce-basic.c
2370
2371 bool
2372 map_reduce_basic (mongoc_database_t *database)
2373 {
2374 bson_t reply;
2375 bson_t *command;
2376 bool res;
2377 bson_error_t error;
2378 mongoc_cursor_t *cursor;
2379 const bson_t *doc;
2380
2381 bool query_done = false;
2382
2383 const char *out_collection_name = "outCollection";
2384 mongoc_collection_t *out_collection;
2385
2386 /* Empty find query */
2387 bson_t find_query = BSON_INITIALIZER;
2388
2389 /* Construct the mapReduce command */
2390
2391 /* Other arguments can also be specified here, like "query" or
2392 "limit" and so on */
2393 command = BCON_NEW ("mapReduce",
2394 BCON_UTF8 (COLLECTION_NAME),
2395 "map",
2396 BCON_CODE (MAPPER),
2397 "reduce",
2398 BCON_CODE (REDUCER),
2399 "out",
2400 BCON_UTF8 (out_collection_name));
2401 res =
2402 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2403
2404 if (!res) {
2405 fprintf (stderr, "MapReduce failed: %s\n", error.message);
2406 goto cleanup;
2407 }
2408
2409 /* Do something with the reply (it doesn't contain the mapReduce results) */
2410 print_res (&reply);
2411
2412 /* Now we'll query outCollection to see what the results are */
2413 out_collection =
2414 mongoc_database_get_collection (database, out_collection_name);
2415 cursor = mongoc_collection_find_with_opts (
2416 out_collection, &find_query, NULL, NULL);
2417 query_done = true;
2418
2419 /* Do something with the results */
2420 while (mongoc_cursor_next (cursor, &doc)) {
2421 print_res (doc);
2422 }
2423
2424 if (mongoc_cursor_error (cursor, &error)) {
2425 fprintf (stderr, "ERROR: %s\n", error.message);
2426 res = false;
2427 goto cleanup;
2428 }
2429
2430 cleanup:
2431 /* cleanup */
2432 if (query_done) {
2433 mongoc_cursor_destroy (cursor);
2434 mongoc_collection_destroy (out_collection);
2435 }
2436
2437 bson_destroy (&reply);
2438 bson_destroy (command);
2439
2440 return res;
2441 }
2442
2443
2444 mapReduce - more complicated example
2445 You must have replica set running for this.
2446
2447 In this example we contact a secondary in the replica set and do an
2448 "inline" map reduce, so the results are returned immediately:
2449
2450 map-reduce-advanced.c
2451
2452 bool
2453 map_reduce_advanced (mongoc_database_t *database)
2454 {
2455 bson_t *command;
2456 bson_error_t error;
2457 bool res = true;
2458 mongoc_cursor_t *cursor;
2459 mongoc_read_prefs_t *read_pref;
2460 const bson_t *doc;
2461
2462 /* Construct the mapReduce command */
2463 /* Other arguments can also be specified here, like "query" or "limit"
2464 and so on */
2465
2466 /* Read the results inline from a secondary replica */
2467 command = BCON_NEW ("mapReduce",
2468 BCON_UTF8 (COLLECTION_NAME),
2469 "map",
2470 BCON_CODE (MAPPER),
2471 "reduce",
2472 BCON_CODE (REDUCER),
2473 "out",
2474 "{",
2475 "inline",
2476 "1",
2477 "}");
2478
2479 read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
2480 cursor = mongoc_database_command (
2481 database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref);
2482
2483 /* Do something with the results */
2484 while (mongoc_cursor_next (cursor, &doc)) {
2485 print_res (doc);
2486 }
2487
2488 if (mongoc_cursor_error (cursor, &error)) {
2489 fprintf (stderr, "ERROR: %s\n", error.message);
2490 res = false;
2491 }
2492
2493 mongoc_cursor_destroy (cursor);
2494 mongoc_read_prefs_destroy (read_pref);
2495 bson_destroy (command);
2496
2497 return res;
2498 }
2499
2500
2501 Running the Examples
2502 Here's how to run the example code
2503
2504 basic-aggregation.c
2505
2506 /*
2507 * Copyright 2016 MongoDB, Inc.
2508 *
2509 * Licensed under the Apache License, Version 2.0 (the "License");
2510 * you may not use this file except in compliance with the License.
2511 * You may obtain a copy of the License at
2512 *
2513 * http://www.apache.org/licenses/LICENSE-2.0
2514 *
2515 * Unless required by applicable law or agreed to in writing, software
2516 * distributed under the License is distributed on an "AS IS" BASIS,
2517 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2518 * See the License for the specific language governing permissions and
2519 * limitations under the License.
2520 */
2521
2522
2523 #include <mongoc/mongoc.h>
2524 #include <stdio.h>
2525
2526
2527 #include "constants.c"
2528
2529 #include "../doc-common-insert.c"
2530 #include "distinct.c"
2531 #include "map-reduce-basic.c"
2532 #include "map-reduce-advanced.c"
2533
2534
2535 int
2536 main (int argc, char *argv[])
2537 {
2538 mongoc_database_t *database = NULL;
2539 mongoc_client_t *client = NULL;
2540 mongoc_collection_t *collection = NULL;
2541 mongoc_uri_t *uri = NULL;
2542 bson_error_t error;
2543 char *host_and_port = NULL;
2544 int exit_code = EXIT_FAILURE;
2545
2546 if (argc != 2) {
2547 fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]);
2548 fprintf (stderr,
2549 "the connection string can be of the following forms:\n");
2550 fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
2551 fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
2552 fprintf (stderr,
2553 "mongodb://user:pass@localhost:27017\t"
2554 "local machine on port 27017, and authenticate with username "
2555 "user and password pass\n");
2556 return exit_code;
2557 }
2558
2559 mongoc_init ();
2560
2561 if (strncmp (argv[1], "mongodb://", 10) == 0) {
2562 host_and_port = bson_strdup (argv[1]);
2563 } else {
2564 host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
2565 }
2566
2567 uri = mongoc_uri_new_with_error (host_and_port, &error);
2568 if (!uri) {
2569 fprintf (stderr,
2570 "failed to parse URI: %s\n"
2571 "error message: %s\n",
2572 host_and_port,
2573 error.message);
2574 goto cleanup;
2575 }
2576
2577 client = mongoc_client_new_from_uri (uri);
2578 if (!client) {
2579 goto cleanup;
2580 }
2581
2582 mongoc_client_set_error_api (client, 2);
2583 database = mongoc_client_get_database (client, "test");
2584 collection = mongoc_database_get_collection (database, COLLECTION_NAME);
2585
2586 printf ("Inserting data\n");
2587 if (!insert_data (collection)) {
2588 goto cleanup;
2589 }
2590
2591 printf ("distinct\n");
2592 if (!distinct (database)) {
2593 goto cleanup;
2594 }
2595
2596 printf ("map reduce\n");
2597 if (!map_reduce_basic (database)) {
2598 goto cleanup;
2599 }
2600
2601 printf ("more complicated map reduce\n");
2602 if (!map_reduce_advanced (database)) {
2603 goto cleanup;
2604 }
2605
2606 exit_code = EXIT_SUCCESS;
2607
2608 cleanup:
2609 if (collection) {
2610 mongoc_collection_destroy (collection);
2611 }
2612
2613 if (database) {
2614 mongoc_database_destroy (database);
2615 }
2616
2617 if (client) {
2618 mongoc_client_destroy (client);
2619 }
2620
2621 if (uri) {
2622 mongoc_uri_destroy (uri);
2623 }
2624
2625 if (host_and_port) {
2626 bson_free (host_and_port);
2627 }
2628
2629 mongoc_cleanup ();
2630 return exit_code;
2631 }
2632
2633
2634 If you want to try the advanced map reduce example with a secondary,
2635 start a replica set (instructions for how to do this can be found
2636 here).
2637
2638 Otherwise, just start an instance of MongoDB:
2639
2640 $ mongod
2641
2642 Now compile and run the example program:
2643
2644 $ cd examples/basic_aggregation/
2645 $ gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0)
2646 $ ./agg-example localhost
2647
2648 Inserting data
2649 distinct
2650 Next double: 2.000000
2651 Next double: 3.000000
2652 map reduce
2653 { "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
2654 { "_id" : "cat", "value" : 63 }
2655 { "_id" : "dog", "value" : 42 }
2656 { "_id" : "mouse", "value" : 21 }
2657 more complicated map reduce
2658 { "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 }
2659
2661 Download and install libmongoc on your system, then open Visual Studio,
2662 select "File→New→Project...", and create a new Win32 Console Applica‐
2663 tion. [image]
2664
2665 Remember to switch the platform from 32-bit to 64-bit: [image]
2666
2667 Right-click on your console application in the Solution Explorer and
2668 select "Properties". Choose to edit properties for "All Configura‐
2669 tions", expand the "C/C++" options and choose "General". Add to the
2670 "Additional Include Directories" these paths:
2671
2672 C:\mongo-c-driver\include\libbson-1.0
2673 C:\mongo-c-driver\include\libmongoc-1.0
2674 [image]
2675
2676 (If you chose a different CMAKE_INSTALL_PREFIX when you ran CMake, your
2677 include paths will be different.)
2678
2679 Also in the Properties dialog, expand the "Linker" options and choose
2680 "Input", and add to the "Additional Dependencies" these libraries:
2681
2682 C:\mongo-c-driver\lib\bson-1.0.lib
2683 C:\mongo-c-driver\lib\mongoc-1.0.lib
2684 [image]
2685
2686 Adding these libraries as dependencies provides linker symbols to build
2687 your application, but to actually run it, libbson's and libmongoc's
2688 DLLs must be in your executable path. Select "Debugging" in the Proper‐
2689 ties dialog, and set the "Environment" option to:
2690
2691 PATH=c:/mongo-c-driver/bin
2692 [image]
2693
2694 Finally, include "mongoc/mongoc.h" in your project's "stdafx.h":
2695
2696 #include <mongoc/mongoc.h>
2697
2698 Static linking
2699 Following the instructions above, you have dynamically linked your ap‐
2700 plication to the libbson and libmongoc DLLs. This is usually the right
2701 choice. If you want to link statically instead, update your "Additional
2702 Dependencies" list by removing bson-1.0.lib and mongoc-1.0.lib and re‐
2703 placing them with these libraries:
2704
2705 C:\mongo-c-driver\lib\bson-static-1.0.lib
2706 C:\mongo-c-driver\lib\mongoc-static-1.0.lib
2707 ws2_32.lib
2708 Secur32.lib
2709 Crypt32.lib
2710 BCrypt.lib
2711 [image]
2712
2713 (To explain the purpose of each library: bson-static-1.0.lib and mon‐
2714 goc-static-1.0.lib are static archives of the driver code. The socket
2715 library ws2_32 is required by libbson, which uses the socket routine
2716 gethostname to help guarantee ObjectId uniqueness. The BCrypt library
2717 is used by libmongoc for TLS connections to MongoDB, and Secur32 and
2718 Crypt32 are required for enterprise authentication methods like Ker‐
2719 beros.)
2720
2721 Finally, define two preprocessor symbols before including mongoc/mon‐
2722 goc.h in your stdafx.h:
2723
2724 #define BSON_STATIC
2725 #define MONGOC_STATIC
2726 #include <mongoc/mongoc.h>
2727
2728 Making these changes to your project is only required for static link‐
2729 ing; for most people, the dynamic-linking instructions above are pre‐
2730 ferred.
2731
2732 Next Steps
2733 Now you can build and debug applications in Visual Studio that use
2734 libbson and libmongoc. Proceed to making-a-connection in the tutorial
2735 to learn how connect to MongoDB and perform operations.
2736
2738 To create indexes on a MongoDB collection, execute the createIndexes
2739 command with a command function like mongoc_database_write_com‐
2740 mand_with_opts or mongoc_collection_write_command_with_opts. See the
2741 MongoDB Manual entry for the createIndexes command for details.
2742
2743 Example
2744 example-create-indexes.c
2745
2746 /* gcc example-create-indexes.c -o example-create-indexes $(pkg-config --cflags
2747 * --libs libmongoc-1.0) */
2748
2749 /* ./example-create-indexes [CONNECTION_STRING [COLLECTION_NAME]] */
2750
2751 #include <mongoc/mongoc.h>
2752 #include <stdio.h>
2753 #include <stdlib.h>
2754
2755 int
2756 main (int argc, char *argv[])
2757 {
2758 mongoc_client_t *client;
2759 const char *uri_string =
2760 "mongodb://127.0.0.1/?appname=create-indexes-example";
2761 mongoc_uri_t *uri;
2762 mongoc_database_t *db;
2763 const char *collection_name = "test";
2764 bson_t keys;
2765 char *index_name;
2766 bson_t *create_indexes;
2767 bson_t reply;
2768 char *reply_str;
2769 bson_error_t error;
2770 bool r;
2771
2772 mongoc_init ();
2773
2774 if (argc > 1) {
2775 uri_string = argv[1];
2776 }
2777
2778 if (argc > 2) {
2779 collection_name = argv[2];
2780 }
2781
2782 uri = mongoc_uri_new_with_error (uri_string, &error);
2783 if (!uri) {
2784 fprintf (stderr,
2785 "failed to parse URI: %s\n"
2786 "error message: %s\n",
2787 uri_string,
2788 error.message);
2789 return EXIT_FAILURE;
2790 }
2791
2792 client = mongoc_client_new_from_uri (uri);
2793 if (!client) {
2794 return EXIT_FAILURE;
2795 }
2796
2797 mongoc_client_set_error_api (client, 2);
2798 db = mongoc_client_get_database (client, "test");
2799
2800 /* ascending index on field "x" */
2801 bson_init (&keys);
2802 BSON_APPEND_INT32 (&keys, "x", 1);
2803 index_name = mongoc_collection_keys_to_index_string (&keys);
2804 create_indexes = BCON_NEW ("createIndexes",
2805 BCON_UTF8 (collection_name),
2806 "indexes",
2807 "[",
2808 "{",
2809 "key",
2810 BCON_DOCUMENT (&keys),
2811 "name",
2812 BCON_UTF8 (index_name),
2813 "}",
2814 "]");
2815
2816 r = mongoc_database_write_command_with_opts (
2817 db, create_indexes, NULL /* opts */, &reply, &error);
2818
2819 reply_str = bson_as_json (&reply, NULL);
2820 printf ("%s\n", reply_str);
2821
2822 if (!r) {
2823 fprintf (stderr, "Error in createIndexes: %s\n", error.message);
2824 }
2825
2826 bson_free (index_name);
2827 bson_free (reply_str);
2828 bson_destroy (&reply);
2829 bson_destroy (create_indexes);
2830 mongoc_database_destroy (db);
2831 mongoc_uri_destroy (uri);
2832 mongoc_client_destroy (client);
2833
2834 mongoc_cleanup ();
2835
2836 return r ? EXIT_SUCCESS : EXIT_FAILURE;
2837 }
2838
2839
2841 GDB
2842 This repository contains a .gdbinit file that contains helper functions
2843 to aid debugging of data structures. GDB will load this file
2844 automatically if you have added the directory which contains the
2845 .gdbinit file to GDB's auto-load safe-path, and you start GDB from the
2846 directory which holds the .gdbinit file.
2847
2848 You can see the safe-path with show auto-load safe-path on a GDB
2849 prompt. You can configure it by setting it in ~/.gdbinit with:
2850
2851 add-auto-load-safe-path /path/to/mongo-c-driver
2852
2853 If you haven't added the path to your auto-load safe-path, or start GDB
2854 in another directory, load the file with:
2855
2856 source path/to/mongo-c-driver/.gdbinit
2857
2858 The .gdbinit file defines the printbson function, which shows the con‐
2859 tents of a bson_t * variable. If you have a local bson_t, then you
2860 must prefix the variable with a &.
2861
2862 An example GDB session looks like:
2863
2864 (gdb) printbson bson
2865 ALLOC [0x555556cd7310 + 0] (len=475)
2866 {
2867 'bool' : true,
2868 'int32' : NumberInt("42"),
2869 'int64' : NumberLong("3000000042"),
2870 'string' : "Stŕìñg",
2871 'objectId' : ObjectID("5A1442F3122D331C3C6757E1"),
2872 'utcDateTime' : UTCDateTime(1511277299031),
2873 'arrayOfInts' : [
2874 '0' : NumberInt("1"),
2875 '1' : NumberInt("2")
2876 ],
2877 'embeddedDocument' : {
2878 'arrayOfStrings' : [
2879 '0' : "one",
2880 '1' : "two"
2881 ],
2882 'double' : 2.718280,
2883 'notherDoc' : {
2884 'true' : NumberInt("1"),
2885 'false' : false
2886 }
2887 },
2888 'binary' : Binary("02", "3031343532333637"),
2889 'regex' : Regex("@[a-z]+@", "im"),
2890 'null' : null,
2891 'js' : JavaScript("print foo"),
2892 'jsws' : JavaScript("print foo") with scope: {
2893 'f' : NumberInt("42"),
2894 'a' : [
2895 '0' : 3.141593,
2896 '1' : 2.718282
2897 ]
2898 },
2899 'timestamp' : Timestamp(4294967295, 4294967295),
2900 'double' : 3.141593
2901 }
2902
2903 LLDB
2904 This repository also includes a script that customizes LLDB's standard
2905 print command to print a bson_t or bson_t * as JSON:
2906
2907 (lldb) print b
2908 (bson_t) $0 = {"x": 1, "y": 2}
2909
2910 The custom bson command provides more options:
2911
2912 (lldb) bson --verbose b
2913 len=19
2914 flags=INLINE|STATIC
2915 {
2916 "x": 1,
2917 "y": 2
2918 }
2919 (lldb) bson --raw b
2920 '\x13\x00\x00\x00\x10x\x00\x01\x00\x00\x00\x10y\x00\x02\x00\x00\x00\x00'
2921
2922 Type help bson for a list of options.
2923
2924 The script requires a build of libbson with debug symbols, and an in‐
2925 stallation of PyMongo. Install PyMongo with:
2926
2927 python -m pip install pymongo
2928
2929 If you see "No module named pip" then you must install pip, then run
2930 the previous command again.
2931
2932 Create a file ~/.lldbinit containing:
2933
2934 command script import /path/to/mongo-c-driver/lldb_bson.py
2935
2936 If you see "bson command installed by lldb_bson" at the beginning of
2937 your LLDB session, you've installed the script correctly.
2938
2940 New in MongoDB 4.2, Client-Side Field Level Encryption (also referred
2941 to as Client-Side Encryption) allows administrators and developers to
2942 encrypt specific data fields in addition to other MongoDB encryption
2943 features.
2944
2945 With Client-Side Encryption, developers can encrypt fields client side
2946 without any server-side configuration or directives. Client-Side En‐
2947 cryption supports workloads where applications must guarantee that
2948 unauthorized parties, including server administrators, cannot read the
2949 encrypted data.
2950
2951 Automatic encryption, where sensitive fields in commands are encrypted
2952 automatically, requires an Enterprise-only process to do query analy‐
2953 sis.
2954
2955 Installation
2956 libmongocrypt
2957 There is a separate library, libmongocrypt, that must be installed
2958 prior to configuring libmongoc to enable Client-Side Encryption.
2959
2960 libmongocrypt depends on libbson. To build libmongoc with Client-Side
2961 Encryption support you must:
2962
2963 1. Install libbson
2964
2965 2. Build and install libmongocrypt
2966
2967 3. Build libmongoc
2968
2969 To install libbson, follow the instructions to install with a package
2970 manager: Install libbson with a Package Manager or build from source
2971 with cmake (disable building libmongoc with -DENABLE_MONGOC=OFF):
2972
2973 $ cd mongo-c-driver
2974 $ mkdir cmake-build && cd cmake-build
2975 $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGOC=OFF ..
2976 $ cmake --build . --target install
2977
2978 To build and install libmongocrypt, clone the repository and configure
2979 as follows:
2980
2981 $ cd libmongocrypt
2982 $ mkdir cmake-build && cd cmake-build
2983 $ cmake -DENABLE_SHARED_BSON=ON ..
2984 $ cmake --build . --target install
2985
2986 Then, you should be able to build libmongoc with Client-Side Encryp‐
2987 tion.
2988
2989 $ cd mongo-c-driver
2990 $ mkdir cmake-build && cd cmake-build
2991 $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGOC=ON -DENABLE_CLIENT_SIDE_ENCRYPTION=ON ..
2992 $ cmake --build . --target install
2993
2994 mongocryptd
2995 The mongocryptd binary is required for automatic Client-Side Encryption
2996 and is included as a component in the MongoDB Enterprise Server pack‐
2997 age. For detailed installation instructions see the MongoDB documenta‐
2998 tion on mongocryptd.
2999
3000 mongocryptd performs the following:
3001
3002 • Parses the automatic encryption rules specified to the database con‐
3003 nection. If the JSON schema contains invalid automatic encryption
3004 syntax or any document validation syntax, mongocryptd returns an er‐
3005 ror.
3006
3007 • Uses the specified automatic encryption rules to mark fields in read
3008 and write operations for encryption.
3009
3010 • Rejects read/write operations that may return unexpected or incorrect
3011 results when applied to an encrypted field. For supported and unsup‐
3012 ported operations, see Read/Write Support with Automatic Field Level
3013 Encryption.
3014
3015 A mongoc_client_t configured with auto encryption will automatically
3016 spawn the mongocryptd process from the application's PATH. Applications
3017 can control the spawning behavior as part of the automatic encryption
3018 options. For example, to set a custom path to the mongocryptd process,
3019 set the mongocryptdSpawnPath with mongoc_auto_encryption_opts_set_ex‐
3020 tra().
3021
3022 bson_t *extra = BCON_NEW ("mongocryptdSpawnPath", "/path/to/mongocryptd");
3023 mongoc_auto_encryption_opts_set_extra (opts, extra);
3024
3025 To control the logging output of mongocryptd pass mongocryptdSpawnArgs
3026 to mongoc_auto_encryption_opts_set_extra():
3027
3028 bson_t *extra = BCON_NEW ("mongocryptdSpawnArgs",
3029 "[", "--logpath=/path/to/mongocryptd.log", "--logappend", "]");
3030 mongoc_auto_encryption_opts_set_extra (opts, extra);
3031
3032 If your application wishes to manage the mongocryptd process manually,
3033 it is possible to disable spawning mongocryptd:
3034
3035 bson_t *extra = BCON_NEW ("mongocryptdBypassSpawn",
3036 BCON_BOOL(true), "mongocryptdURI", "mongodb://localhost:27020");
3037 mongoc_auto_encryption_opts_set_extra (opts, extra);
3038
3039 mongocryptd is only responsible for supporting automatic Client-Side
3040 Encryption in the driver and does not itself perform any encryption or
3041 decryption.
3042
3043 Automatic Client-Side Field Level Encryption
3044 Automatic Client-Side Encryption is enabled by calling mon‐
3045 goc_client_enable_auto_encryption() on a mongoc_client_t. The following
3046 examples show how to set up automatic client-side field level encryp‐
3047 tion using mongoc_client_encryption_t to create a new encryption data
3048 key.
3049
3050 NOTE:
3051 Automatic client-side field level encryption requires MongoDB 4.2
3052 enterprise or a MongoDB 4.2 Atlas cluster. The community version of
3053 the server supports automatic decryption as well as Explicit Encryp‐
3054 tion.
3055
3056 Providing Local Automatic Encryption Rules
3057 The following example shows how to specify automatic encryption rules
3058 using a schema map set with mongoc_auto_encryp‐
3059 tion_opts_set_schema_map(). The automatic encryption rules are ex‐
3060 pressed using a strict subset of the JSON Schema syntax.
3061
3062 Supplying a schema map provides more security than relying on JSON
3063 Schemas obtained from the server. It protects against a malicious
3064 server advertising a false JSON Schema, which could trick the client
3065 into sending unencrypted data that should be encrypted.
3066
3067 JSON Schemas supplied in the schema map only apply to configuring auto‐
3068 matic client-side field level encryption. Other validation rules in the
3069 JSON schema will not be enforced by the driver and will result in an
3070 error:
3071
3072 client-side-encryption-schema-map.c
3073
3074 #include <mongoc/mongoc.h>
3075 #include <stdio.h>
3076 #include <stdlib.h>
3077
3078 #include "client-side-encryption-helpers.h"
3079
3080 /* Helper method to create a new data key in the key vault, a schema to use that
3081 * key, and writes the schema to a file for later use. */
3082 static bool
3083 create_schema_file (bson_t *kms_providers,
3084 const char *keyvault_db,
3085 const char *keyvault_coll,
3086 mongoc_client_t *keyvault_client,
3087 bson_error_t *error)
3088 {
3089 mongoc_client_encryption_t *client_encryption = NULL;
3090 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3091 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3092 bson_value_t datakey_id = {0};
3093 char *keyaltnames[] = {"mongoc_encryption_example_1"};
3094 bson_t *schema = NULL;
3095 char *schema_string = NULL;
3096 size_t schema_string_len;
3097 FILE *outfile = NULL;
3098 bool ret = false;
3099
3100 client_encryption_opts = mongoc_client_encryption_opts_new ();
3101 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3102 kms_providers);
3103 mongoc_client_encryption_opts_set_keyvault_namespace (
3104 client_encryption_opts, keyvault_db, keyvault_coll);
3105 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3106 keyvault_client);
3107
3108 client_encryption =
3109 mongoc_client_encryption_new (client_encryption_opts, error);
3110 if (!client_encryption) {
3111 goto fail;
3112 }
3113
3114 /* Create a new data key and json schema for the encryptedField.
3115 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3116 */
3117 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3118 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3119 datakey_opts, keyaltnames, 1);
3120 if (!mongoc_client_encryption_create_datakey (
3121 client_encryption, "local", datakey_opts, &datakey_id, error)) {
3122 goto fail;
3123 }
3124
3125 /* Create a schema describing that "encryptedField" is a string encrypted
3126 * with the newly created data key using deterministic encryption. */
3127 schema = BCON_NEW ("properties",
3128 "{",
3129 "encryptedField",
3130 "{",
3131 "encrypt",
3132 "{",
3133 "keyId",
3134 "[",
3135 BCON_BIN (datakey_id.value.v_binary.subtype,
3136 datakey_id.value.v_binary.data,
3137 datakey_id.value.v_binary.data_len),
3138 "]",
3139 "bsonType",
3140 "string",
3141 "algorithm",
3142 MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3143 "}",
3144 "}",
3145 "}",
3146 "bsonType",
3147 "object");
3148
3149 /* Use canonical JSON so that other drivers and tools will be
3150 * able to parse the MongoDB extended JSON file. */
3151 schema_string = bson_as_canonical_extended_json (schema, &schema_string_len);
3152 outfile = fopen ("jsonSchema.json", "w");
3153 if (0 == fwrite (schema_string, sizeof (char), schema_string_len, outfile)) {
3154 fprintf (stderr, "failed to write to file\n");
3155 goto fail;
3156 }
3157
3158 ret = true;
3159 fail:
3160 mongoc_client_encryption_destroy (client_encryption);
3161 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3162 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3163 bson_free (schema_string);
3164 bson_destroy (schema);
3165 bson_value_destroy (&datakey_id);
3166 if (outfile) {
3167 fclose (outfile);
3168 }
3169 return true;
3170 }
3171
3172 /* This example demonstrates how to use automatic encryption with a client-side
3173 * schema map using the enterprise version of MongoDB */
3174 int
3175 main (int argc, char **argv)
3176 {
3177 /* The collection used to store the encryption data keys. */
3178 #define KEYVAULT_DB "encryption"
3179 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3180 /* The collection used to store the encrypted documents in this example. */
3181 #define ENCRYPTED_DB "test"
3182 #define ENCRYPTED_COLL "coll"
3183
3184 int exit_status = EXIT_FAILURE;
3185 bool ret;
3186 uint8_t *local_masterkey = NULL;
3187 uint32_t local_masterkey_len;
3188 bson_t *kms_providers = NULL;
3189 bson_error_t error = {0};
3190 bson_t *index_keys = NULL;
3191 char *index_name = NULL;
3192 bson_t *create_index_cmd = NULL;
3193 bson_json_reader_t *reader = NULL;
3194 bson_t schema = BSON_INITIALIZER;
3195 bson_t *schema_map = NULL;
3196
3197 /* The MongoClient used to access the key vault (keyvault_namespace). */
3198 mongoc_client_t *keyvault_client = NULL;
3199 mongoc_collection_t *keyvault_coll = NULL;
3200 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3201 mongoc_client_t *client = NULL;
3202 mongoc_collection_t *coll = NULL;
3203 bson_t *to_insert = NULL;
3204 mongoc_client_t *unencrypted_client = NULL;
3205 mongoc_collection_t *unencrypted_coll = NULL;
3206
3207 mongoc_init ();
3208
3209 /* Configure the master key. This must be the same master key that was used
3210 * to create the encryption key. */
3211 local_masterkey =
3212 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3213 if (!local_masterkey || local_masterkey_len != 96) {
3214 fprintf (stderr,
3215 "Specify LOCAL_MASTERKEY environment variable as a "
3216 "secure random 96 byte hex value.\n");
3217 goto fail;
3218 }
3219
3220 kms_providers = BCON_NEW ("local",
3221 "{",
3222 "key",
3223 BCON_BIN (0, local_masterkey, local_masterkey_len),
3224 "}");
3225
3226 /* Set up the key vault for this example. */
3227 keyvault_client = mongoc_client_new (
3228 "mongodb://localhost/?appname=client-side-encryption-keyvault");
3229 keyvault_coll = mongoc_client_get_collection (
3230 keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3231 mongoc_collection_drop (keyvault_coll, NULL);
3232
3233 /* Create a unique index to ensure that two data keys cannot share the same
3234 * keyAltName. This is recommended practice for the key vault. */
3235 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3236 index_name = mongoc_collection_keys_to_index_string (index_keys);
3237 create_index_cmd = BCON_NEW ("createIndexes",
3238 KEYVAULT_COLL,
3239 "indexes",
3240 "[",
3241 "{",
3242 "key",
3243 BCON_DOCUMENT (index_keys),
3244 "name",
3245 index_name,
3246 "unique",
3247 BCON_BOOL (true),
3248 "partialFilterExpression",
3249 "{",
3250 "keyAltNames",
3251 "{",
3252 "$exists",
3253 BCON_BOOL (true),
3254 "}",
3255 "}",
3256 "}",
3257 "]");
3258 ret = mongoc_client_command_simple (keyvault_client,
3259 KEYVAULT_DB,
3260 create_index_cmd,
3261 NULL /* read prefs */,
3262 NULL /* reply */,
3263 &error);
3264
3265 if (!ret) {
3266 goto fail;
3267 }
3268
3269 /* Create a new data key and a schema using it for encryption. Save the
3270 * schema to the file jsonSchema.json */
3271 ret = create_schema_file (
3272 kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3273
3274 if (!ret) {
3275 goto fail;
3276 }
3277
3278 /* Load the JSON Schema and construct the local schema_map option. */
3279 reader = bson_json_reader_new_from_file ("jsonSchema.json", &error);
3280 if (!reader) {
3281 goto fail;
3282 }
3283
3284 bson_json_reader_read (reader, &schema, &error);
3285
3286 /* Construct the schema map, mapping the namespace of the collection to the
3287 * schema describing encryption. */
3288 schema_map =
3289 BCON_NEW (ENCRYPTED_DB "." ENCRYPTED_COLL, BCON_DOCUMENT (&schema));
3290
3291 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3292 mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3293 keyvault_client);
3294 mongoc_auto_encryption_opts_set_keyvault_namespace (
3295 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3296 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3297 kms_providers);
3298 mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts,
3299 schema_map);
3300
3301 client =
3302 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3303
3304 /* Enable automatic encryption. It will determine that encryption is
3305 * necessary from the schema map instead of relying on the server to provide
3306 * a schema. */
3307 ret = mongoc_client_enable_auto_encryption (
3308 client, auto_encryption_opts, &error);
3309 if (!ret) {
3310 goto fail;
3311 }
3312
3313 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3314
3315 /* Clear old data */
3316 mongoc_collection_drop (coll, NULL);
3317
3318 to_insert = BCON_NEW ("encryptedField", "123456789");
3319 ret = mongoc_collection_insert_one (
3320 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3321 if (!ret) {
3322 goto fail;
3323 }
3324 printf ("decrypted document: ");
3325 if (!print_one_document (coll, &error)) {
3326 goto fail;
3327 }
3328 printf ("\n");
3329
3330 unencrypted_client = mongoc_client_new (
3331 "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3332 unencrypted_coll = mongoc_client_get_collection (
3333 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3334 printf ("encrypted document: ");
3335 if (!print_one_document (unencrypted_coll, &error)) {
3336 goto fail;
3337 }
3338 printf ("\n");
3339
3340 exit_status = EXIT_SUCCESS;
3341 fail:
3342 if (error.code) {
3343 fprintf (stderr, "error: %s\n", error.message);
3344 }
3345
3346 bson_free (local_masterkey);
3347 bson_destroy (kms_providers);
3348 mongoc_collection_destroy (keyvault_coll);
3349 bson_destroy (index_keys);
3350 bson_free (index_name);
3351 bson_destroy (create_index_cmd);
3352 bson_json_reader_destroy (reader);
3353 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3354 mongoc_collection_destroy (coll);
3355 mongoc_client_destroy (client);
3356 bson_destroy (to_insert);
3357 mongoc_collection_destroy (unencrypted_coll);
3358 mongoc_client_destroy (unencrypted_client);
3359 mongoc_client_destroy (keyvault_client);
3360 bson_destroy (&schema);
3361 bson_destroy (schema_map);
3362 mongoc_cleanup ();
3363 return exit_status;
3364 }
3365
3366 Server-Side Field Level Encryption Enforcement
3367 The MongoDB 4.2 server supports using schema validation to enforce en‐
3368 cryption of specific fields in a collection. This schema validation
3369 will prevent an application from inserting unencrypted values for any
3370 fields marked with the "encrypt" JSON schema keyword.
3371
3372 The following example shows how to set up automatic client-side field
3373 level encryption using mongoc_client_encryption_t to create a new en‐
3374 cryption data key and create a collection with the Automatic Encryption
3375 JSON Schema Syntax:
3376
3377 client-side-encryption-server-schema.c
3378
3379 #include <mongoc/mongoc.h>
3380 #include <stdio.h>
3381 #include <stdlib.h>
3382
3383 #include "client-side-encryption-helpers.h"
3384
3385 /* Helper method to create and return a JSON schema to use for encryption.
3386 The caller will use the returned schema for server-side encryption validation.
3387 */
3388 static bson_t *
3389 create_schema (bson_t *kms_providers,
3390 const char *keyvault_db,
3391 const char *keyvault_coll,
3392 mongoc_client_t *keyvault_client,
3393 bson_error_t *error)
3394 {
3395 mongoc_client_encryption_t *client_encryption = NULL;
3396 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3397 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3398 bson_value_t datakey_id = {0};
3399 char *keyaltnames[] = {"mongoc_encryption_example_2"};
3400 bson_t *schema = NULL;
3401
3402 client_encryption_opts = mongoc_client_encryption_opts_new ();
3403 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3404 kms_providers);
3405 mongoc_client_encryption_opts_set_keyvault_namespace (
3406 client_encryption_opts, keyvault_db, keyvault_coll);
3407 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3408 keyvault_client);
3409
3410 client_encryption =
3411 mongoc_client_encryption_new (client_encryption_opts, error);
3412 if (!client_encryption) {
3413 goto fail;
3414 }
3415
3416 /* Create a new data key and json schema for the encryptedField.
3417 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3418 */
3419 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3420 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3421 datakey_opts, keyaltnames, 1);
3422 if (!mongoc_client_encryption_create_datakey (
3423 client_encryption, "local", datakey_opts, &datakey_id, error)) {
3424 goto fail;
3425 }
3426
3427 /* Create a schema describing that "encryptedField" is a string encrypted
3428 * with the newly created data key using deterministic encryption. */
3429 schema = BCON_NEW ("properties",
3430 "{",
3431 "encryptedField",
3432 "{",
3433 "encrypt",
3434 "{",
3435 "keyId",
3436 "[",
3437 BCON_BIN (datakey_id.value.v_binary.subtype,
3438 datakey_id.value.v_binary.data,
3439 datakey_id.value.v_binary.data_len),
3440 "]",
3441 "bsonType",
3442 "string",
3443 "algorithm",
3444 MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3445 "}",
3446 "}",
3447 "}",
3448 "bsonType",
3449 "object");
3450
3451 fail:
3452 mongoc_client_encryption_destroy (client_encryption);
3453 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3454 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3455 bson_value_destroy (&datakey_id);
3456 return schema;
3457 }
3458
3459 /* This example demonstrates how to use automatic encryption with a server-side
3460 * schema using the enterprise version of MongoDB */
3461 int
3462 main (int argc, char **argv)
3463 {
3464 /* The collection used to store the encryption data keys. */
3465 #define KEYVAULT_DB "encryption"
3466 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3467 /* The collection used to store the encrypted documents in this example. */
3468 #define ENCRYPTED_DB "test"
3469 #define ENCRYPTED_COLL "coll"
3470
3471 int exit_status = EXIT_FAILURE;
3472 bool ret;
3473 uint8_t *local_masterkey = NULL;
3474 uint32_t local_masterkey_len;
3475 bson_t *kms_providers = NULL;
3476 bson_error_t error = {0};
3477 bson_t *index_keys = NULL;
3478 char *index_name = NULL;
3479 bson_t *create_index_cmd = NULL;
3480 bson_json_reader_t *reader = NULL;
3481 bson_t *schema = NULL;
3482
3483 /* The MongoClient used to access the key vault (keyvault_namespace). */
3484 mongoc_client_t *keyvault_client = NULL;
3485 mongoc_collection_t *keyvault_coll = NULL;
3486 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3487 mongoc_client_t *client = NULL;
3488 mongoc_collection_t *coll = NULL;
3489 bson_t *to_insert = NULL;
3490 mongoc_client_t *unencrypted_client = NULL;
3491 mongoc_collection_t *unencrypted_coll = NULL;
3492 bson_t *create_cmd = NULL;
3493 bson_t *create_cmd_opts = NULL;
3494 mongoc_write_concern_t *wc = NULL;
3495
3496 mongoc_init ();
3497
3498 /* Configure the master key. This must be the same master key that was used
3499 * to create
3500 * the encryption key. */
3501 local_masterkey =
3502 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3503 if (!local_masterkey || local_masterkey_len != 96) {
3504 fprintf (stderr,
3505 "Specify LOCAL_MASTERKEY environment variable as a "
3506 "secure random 96 byte hex value.\n");
3507 goto fail;
3508 }
3509
3510 kms_providers = BCON_NEW ("local",
3511 "{",
3512 "key",
3513 BCON_BIN (0, local_masterkey, local_masterkey_len),
3514 "}");
3515
3516 /* Set up the key vault for this example. */
3517 keyvault_client = mongoc_client_new (
3518 "mongodb://localhost/?appname=client-side-encryption-keyvault");
3519 keyvault_coll = mongoc_client_get_collection (
3520 keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3521 mongoc_collection_drop (keyvault_coll, NULL);
3522
3523 /* Create a unique index to ensure that two data keys cannot share the same
3524 * keyAltName. This is recommended practice for the key vault. */
3525 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3526 index_name = mongoc_collection_keys_to_index_string (index_keys);
3527 create_index_cmd = BCON_NEW ("createIndexes",
3528 KEYVAULT_COLL,
3529 "indexes",
3530 "[",
3531 "{",
3532 "key",
3533 BCON_DOCUMENT (index_keys),
3534 "name",
3535 index_name,
3536 "unique",
3537 BCON_BOOL (true),
3538 "partialFilterExpression",
3539 "{",
3540 "keyAltNames",
3541 "{",
3542 "$exists",
3543 BCON_BOOL (true),
3544 "}",
3545 "}",
3546 "}",
3547 "]");
3548 ret = mongoc_client_command_simple (keyvault_client,
3549 KEYVAULT_DB,
3550 create_index_cmd,
3551 NULL /* read prefs */,
3552 NULL /* reply */,
3553 &error);
3554
3555 if (!ret) {
3556 goto fail;
3557 }
3558
3559 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3560 mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3561 keyvault_client);
3562 mongoc_auto_encryption_opts_set_keyvault_namespace (
3563 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3564 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3565 kms_providers);
3566 schema = create_schema (
3567 kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3568
3569 if (!schema) {
3570 goto fail;
3571 }
3572
3573 client =
3574 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3575 ret = mongoc_client_enable_auto_encryption (
3576 client, auto_encryption_opts, &error);
3577 if (!ret) {
3578 goto fail;
3579 }
3580
3581 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3582
3583 /* Clear old data */
3584 mongoc_collection_drop (coll, NULL);
3585
3586 /* Create the collection with the encryption JSON Schema. */
3587 create_cmd = BCON_NEW ("create",
3588 ENCRYPTED_COLL,
3589 "validator",
3590 "{",
3591 "$jsonSchema",
3592 BCON_DOCUMENT (schema),
3593 "}");
3594 wc = mongoc_write_concern_new ();
3595 mongoc_write_concern_set_wmajority (wc, 0);
3596 create_cmd_opts = bson_new ();
3597 mongoc_write_concern_append (wc, create_cmd_opts);
3598 ret = mongoc_client_command_with_opts (client,
3599 ENCRYPTED_DB,
3600 create_cmd,
3601 NULL /* read prefs */,
3602 create_cmd_opts,
3603 NULL /* reply */,
3604 &error);
3605 if (!ret) {
3606 goto fail;
3607 }
3608
3609 to_insert = BCON_NEW ("encryptedField", "123456789");
3610 ret = mongoc_collection_insert_one (
3611 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3612 if (!ret) {
3613 goto fail;
3614 }
3615 printf ("decrypted document: ");
3616 if (!print_one_document (coll, &error)) {
3617 goto fail;
3618 }
3619 printf ("\n");
3620
3621 unencrypted_client = mongoc_client_new (
3622 "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3623 unencrypted_coll = mongoc_client_get_collection (
3624 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3625 printf ("encrypted document: ");
3626 if (!print_one_document (unencrypted_coll, &error)) {
3627 goto fail;
3628 }
3629 printf ("\n");
3630
3631 /* Expect a server-side error if inserting with the unencrypted collection.
3632 */
3633 ret = mongoc_collection_insert_one (
3634 unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3635 if (!ret) {
3636 printf ("insert with unencrypted collection failed: %s\n", error.message);
3637 memset (&error, 0, sizeof (error));
3638 }
3639
3640 exit_status = EXIT_SUCCESS;
3641 fail:
3642 if (error.code) {
3643 fprintf (stderr, "error: %s\n", error.message);
3644 }
3645
3646 bson_free (local_masterkey);
3647 bson_destroy (kms_providers);
3648 mongoc_collection_destroy (keyvault_coll);
3649 bson_destroy (index_keys);
3650 bson_free (index_name);
3651 bson_destroy (create_index_cmd);
3652 bson_json_reader_destroy (reader);
3653 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3654 mongoc_collection_destroy (coll);
3655 mongoc_client_destroy (client);
3656 bson_destroy (to_insert);
3657 mongoc_collection_destroy (unencrypted_coll);
3658 mongoc_client_destroy (unencrypted_client);
3659 mongoc_client_destroy (keyvault_client);
3660 bson_destroy (schema);
3661 bson_destroy (create_cmd);
3662 bson_destroy (create_cmd_opts);
3663 mongoc_write_concern_destroy (wc);
3664
3665 mongoc_cleanup ();
3666 return exit_status;
3667 }
3668
3669 Explicit Encryption
3670 Explicit encryption is a MongoDB community feature and does not use the
3671 mongocryptd process. Explicit encryption is provided by the mon‐
3672 goc_client_encryption_t class, for example:
3673
3674 client-side-encryption-explicit.c
3675
3676 #include <mongoc/mongoc.h>
3677 #include <stdio.h>
3678 #include <stdlib.h>
3679
3680 #include "client-side-encryption-helpers.h"
3681
3682 /* This example demonstrates how to use explicit encryption and decryption using
3683 * the community version of MongoDB */
3684 int
3685 main (int argc, char **argv)
3686 {
3687 /* The collection used to store the encryption data keys. */
3688 #define KEYVAULT_DB "encryption"
3689 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3690 /* The collection used to store the encrypted documents in this example. */
3691 #define ENCRYPTED_DB "test"
3692 #define ENCRYPTED_COLL "coll"
3693
3694 int exit_status = EXIT_FAILURE;
3695 bool ret;
3696 uint8_t *local_masterkey = NULL;
3697 uint32_t local_masterkey_len;
3698 bson_t *kms_providers = NULL;
3699 bson_error_t error = {0};
3700 bson_t *index_keys = NULL;
3701 char *index_name = NULL;
3702 bson_t *create_index_cmd = NULL;
3703 bson_t *schema = NULL;
3704 mongoc_client_t *client = NULL;
3705 mongoc_collection_t *coll = NULL;
3706 mongoc_collection_t *keyvault_coll = NULL;
3707 bson_t *to_insert = NULL;
3708 bson_t *create_cmd = NULL;
3709 bson_t *create_cmd_opts = NULL;
3710 mongoc_write_concern_t *wc = NULL;
3711 mongoc_client_encryption_t *client_encryption = NULL;
3712 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3713 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3714 char *keyaltnames[] = {"mongoc_encryption_example_3"};
3715 bson_value_t datakey_id = {0};
3716 bson_value_t encrypted_field = {0};
3717 bson_value_t to_encrypt = {0};
3718 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3719 bson_value_t decrypted = {0};
3720
3721 mongoc_init ();
3722
3723 /* Configure the master key. This must be the same master key that was used
3724 * to create the encryption key. */
3725 local_masterkey =
3726 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3727 if (!local_masterkey || local_masterkey_len != 96) {
3728 fprintf (stderr,
3729 "Specify LOCAL_MASTERKEY environment variable as a "
3730 "secure random 96 byte hex value.\n");
3731 goto fail;
3732 }
3733
3734 kms_providers = BCON_NEW ("local",
3735 "{",
3736 "key",
3737 BCON_BIN (0, local_masterkey, local_masterkey_len),
3738 "}");
3739
3740 /* The mongoc_client_t used to read/write application data. */
3741 client =
3742 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3743 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3744
3745 /* Clear old data */
3746 mongoc_collection_drop (coll, NULL);
3747
3748 /* Set up the key vault for this example. */
3749 keyvault_coll =
3750 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3751 mongoc_collection_drop (keyvault_coll, NULL);
3752
3753 /* Create a unique index to ensure that two data keys cannot share the same
3754 * keyAltName. This is recommended practice for the key vault. */
3755 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3756 index_name = mongoc_collection_keys_to_index_string (index_keys);
3757 create_index_cmd = BCON_NEW ("createIndexes",
3758 KEYVAULT_COLL,
3759 "indexes",
3760 "[",
3761 "{",
3762 "key",
3763 BCON_DOCUMENT (index_keys),
3764 "name",
3765 index_name,
3766 "unique",
3767 BCON_BOOL (true),
3768 "partialFilterExpression",
3769 "{",
3770 "keyAltNames",
3771 "{",
3772 "$exists",
3773 BCON_BOOL (true),
3774 "}",
3775 "}",
3776 "}",
3777 "]");
3778 ret = mongoc_client_command_simple (client,
3779 KEYVAULT_DB,
3780 create_index_cmd,
3781 NULL /* read prefs */,
3782 NULL /* reply */,
3783 &error);
3784
3785 if (!ret) {
3786 goto fail;
3787 }
3788
3789 client_encryption_opts = mongoc_client_encryption_opts_new ();
3790 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3791 kms_providers);
3792 mongoc_client_encryption_opts_set_keyvault_namespace (
3793 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3794
3795 /* Set a mongoc_client_t to use for reading/writing to the key vault. This
3796 * can be the same mongoc_client_t used by the main application. */
3797 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3798 client);
3799 client_encryption =
3800 mongoc_client_encryption_new (client_encryption_opts, &error);
3801 if (!client_encryption) {
3802 goto fail;
3803 }
3804
3805 /* Create a new data key for the encryptedField.
3806 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3807 */
3808 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3809 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3810 datakey_opts, keyaltnames, 1);
3811 if (!mongoc_client_encryption_create_datakey (
3812 client_encryption, "local", datakey_opts, &datakey_id, &error)) {
3813 goto fail;
3814 }
3815
3816 /* Explicitly encrypt a field */
3817 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
3818 mongoc_client_encryption_encrypt_opts_set_algorithm (
3819 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
3820 mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id);
3821 to_encrypt.value_type = BSON_TYPE_UTF8;
3822 to_encrypt.value.v_utf8.str = "123456789";
3823 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
3824
3825 ret = mongoc_client_encryption_encrypt (
3826 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
3827 if (!ret) {
3828 goto fail;
3829 }
3830
3831 to_insert = bson_new ();
3832 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
3833 ret = mongoc_collection_insert_one (
3834 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3835 if (!ret) {
3836 goto fail;
3837 }
3838
3839 printf ("encrypted document: ");
3840 if (!print_one_document (coll, &error)) {
3841 goto fail;
3842 }
3843 printf ("\n");
3844
3845 /* Explicitly decrypt a field */
3846 ret = mongoc_client_encryption_decrypt (
3847 client_encryption, &encrypted_field, &decrypted, &error);
3848 if (!ret) {
3849 goto fail;
3850 }
3851 printf ("decrypted value: %s\n", decrypted.value.v_utf8.str);
3852
3853 exit_status = EXIT_SUCCESS;
3854 fail:
3855 if (error.code) {
3856 fprintf (stderr, "error: %s\n", error.message);
3857 }
3858
3859 bson_free (local_masterkey);
3860 bson_destroy (kms_providers);
3861 mongoc_collection_destroy (keyvault_coll);
3862 bson_destroy (index_keys);
3863 bson_free (index_name);
3864 bson_destroy (create_index_cmd);
3865 mongoc_collection_destroy (coll);
3866 mongoc_client_destroy (client);
3867 bson_destroy (to_insert);
3868 bson_destroy (schema);
3869 bson_destroy (create_cmd);
3870 bson_destroy (create_cmd_opts);
3871 mongoc_write_concern_destroy (wc);
3872 mongoc_client_encryption_destroy (client_encryption);
3873 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3874 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3875 bson_value_destroy (&encrypted_field);
3876 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
3877 bson_value_destroy (&decrypted);
3878 bson_value_destroy (&datakey_id);
3879
3880 mongoc_cleanup ();
3881 return exit_status;
3882 }
3883
3884 Explicit Encryption with Automatic Decryption
3885 Although automatic encryption requires MongoDB 4.2 enterprise or a Mon‐
3886 goDB 4.2 Atlas cluster, automatic decryption is supported for all
3887 users. To configure automatic decryption without automatic encryption
3888 set bypass_auto_encryption=True in mongoc_auto_encryption_opts_t:
3889
3890 client-side-encryption-auto-decryption.c
3891
3892 #include <mongoc/mongoc.h>
3893 #include <stdio.h>
3894 #include <stdlib.h>
3895
3896 #include "client-side-encryption-helpers.h"
3897
3898 /* This example demonstrates how to set up automatic decryption without
3899 * automatic encryption using the community version of MongoDB */
3900 int
3901 main (int argc, char **argv)
3902 {
3903 /* The collection used to store the encryption data keys. */
3904 #define KEYVAULT_DB "encryption"
3905 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3906 /* The collection used to store the encrypted documents in this example. */
3907 #define ENCRYPTED_DB "test"
3908 #define ENCRYPTED_COLL "coll"
3909
3910 int exit_status = EXIT_FAILURE;
3911 bool ret;
3912 uint8_t *local_masterkey = NULL;
3913 uint32_t local_masterkey_len;
3914 bson_t *kms_providers = NULL;
3915 bson_error_t error = {0};
3916 bson_t *index_keys = NULL;
3917 char *index_name = NULL;
3918 bson_t *create_index_cmd = NULL;
3919 bson_t *schema = NULL;
3920 mongoc_client_t *client = NULL;
3921 mongoc_collection_t *coll = NULL;
3922 mongoc_collection_t *keyvault_coll = NULL;
3923 bson_t *to_insert = NULL;
3924 bson_t *create_cmd = NULL;
3925 bson_t *create_cmd_opts = NULL;
3926 mongoc_write_concern_t *wc = NULL;
3927 mongoc_client_encryption_t *client_encryption = NULL;
3928 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3929 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3930 char *keyaltnames[] = {"mongoc_encryption_example_4"};
3931 bson_value_t datakey_id = {0};
3932 bson_value_t encrypted_field = {0};
3933 bson_value_t to_encrypt = {0};
3934 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3935 bson_value_t decrypted = {0};
3936 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3937 mongoc_client_t *unencrypted_client = NULL;
3938 mongoc_collection_t *unencrypted_coll = NULL;
3939
3940 mongoc_init ();
3941
3942 /* Configure the master key. This must be the same master key that was used
3943 * to create the encryption key. */
3944 local_masterkey =
3945 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3946 if (!local_masterkey || local_masterkey_len != 96) {
3947 fprintf (stderr,
3948 "Specify LOCAL_MASTERKEY environment variable as a "
3949 "secure random 96 byte hex value.\n");
3950 goto fail;
3951 }
3952
3953 kms_providers = BCON_NEW ("local",
3954 "{",
3955 "key",
3956 BCON_BIN (0, local_masterkey, local_masterkey_len),
3957 "}");
3958
3959 client =
3960 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3961 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3962 mongoc_auto_encryption_opts_set_keyvault_namespace (
3963 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3964 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3965 kms_providers);
3966
3967 /* Setting bypass_auto_encryption to true disables automatic encryption but
3968 * keeps the automatic decryption behavior. bypass_auto_encryption will also
3969 * disable spawning mongocryptd */
3970 mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts,
3971 true);
3972
3973 /* Once bypass_auto_encryption is set, community users can enable auto
3974 * encryption on the client. This will, in fact, only perform automatic
3975 * decryption. */
3976 ret = mongoc_client_enable_auto_encryption (
3977 client, auto_encryption_opts, &error);
3978 if (!ret) {
3979 goto fail;
3980 }
3981
3982 /* Now that automatic decryption is on, we can test it by inserting a
3983 * document with an explicitly encrypted value into the collection. When we
3984 * look up the document later, it should be automatically decrypted for us.
3985 */
3986 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3987
3988 /* Clear old data */
3989 mongoc_collection_drop (coll, NULL);
3990
3991 /* Set up the key vault for this example. */
3992 keyvault_coll =
3993 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3994 mongoc_collection_drop (keyvault_coll, NULL);
3995
3996 /* Create a unique index to ensure that two data keys cannot share the same
3997 * keyAltName. This is recommended practice for the key vault. */
3998 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3999 index_name = mongoc_collection_keys_to_index_string (index_keys);
4000 create_index_cmd = BCON_NEW ("createIndexes",
4001 KEYVAULT_COLL,
4002 "indexes",
4003 "[",
4004 "{",
4005 "key",
4006 BCON_DOCUMENT (index_keys),
4007 "name",
4008 index_name,
4009 "unique",
4010 BCON_BOOL (true),
4011 "partialFilterExpression",
4012 "{",
4013 "keyAltNames",
4014 "{",
4015 "$exists",
4016 BCON_BOOL (true),
4017 "}",
4018 "}",
4019 "}",
4020 "]");
4021 ret = mongoc_client_command_simple (client,
4022 KEYVAULT_DB,
4023 create_index_cmd,
4024 NULL /* read prefs */,
4025 NULL /* reply */,
4026 &error);
4027
4028 if (!ret) {
4029 goto fail;
4030 }
4031
4032 client_encryption_opts = mongoc_client_encryption_opts_new ();
4033 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
4034 kms_providers);
4035 mongoc_client_encryption_opts_set_keyvault_namespace (
4036 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
4037
4038 /* The key vault client is used for reading to/from the key vault. This can
4039 * be the same mongoc_client_t used by the application. */
4040 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
4041 client);
4042 client_encryption =
4043 mongoc_client_encryption_new (client_encryption_opts, &error);
4044 if (!client_encryption) {
4045 goto fail;
4046 }
4047
4048 /* Create a new data key for the encryptedField.
4049 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
4050 */
4051 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
4052 mongoc_client_encryption_datakey_opts_set_keyaltnames (
4053 datakey_opts, keyaltnames, 1);
4054 ret = mongoc_client_encryption_create_datakey (
4055 client_encryption, "local", datakey_opts, &datakey_id, &error);
4056 if (!ret) {
4057 goto fail;
4058 }
4059
4060 /* Explicitly encrypt a field. */
4061 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
4062 mongoc_client_encryption_encrypt_opts_set_algorithm (
4063 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
4064 mongoc_client_encryption_encrypt_opts_set_keyaltname (
4065 encrypt_opts, "mongoc_encryption_example_4");
4066 to_encrypt.value_type = BSON_TYPE_UTF8;
4067 to_encrypt.value.v_utf8.str = "123456789";
4068 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
4069
4070 ret = mongoc_client_encryption_encrypt (
4071 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
4072 if (!ret) {
4073 goto fail;
4074 }
4075
4076 to_insert = bson_new ();
4077 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
4078 ret = mongoc_collection_insert_one (
4079 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
4080 if (!ret) {
4081 goto fail;
4082 }
4083
4084 /* When we retrieve the document, any encrypted fields will get automatically
4085 * decrypted by the driver. */
4086 printf ("decrypted document: ");
4087 if (!print_one_document (coll, &error)) {
4088 goto fail;
4089 }
4090 printf ("\n");
4091
4092 unencrypted_client =
4093 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
4094 unencrypted_coll = mongoc_client_get_collection (
4095 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
4096
4097 printf ("encrypted document: ");
4098 if (!print_one_document (unencrypted_coll, &error)) {
4099 goto fail;
4100 }
4101 printf ("\n");
4102
4103 exit_status = EXIT_SUCCESS;
4104 fail:
4105 if (error.code) {
4106 fprintf (stderr, "error: %s\n", error.message);
4107 }
4108
4109 bson_free (local_masterkey);
4110 bson_destroy (kms_providers);
4111 mongoc_collection_destroy (keyvault_coll);
4112 bson_destroy (index_keys);
4113 bson_free (index_name);
4114 bson_destroy (create_index_cmd);
4115 mongoc_collection_destroy (coll);
4116 mongoc_client_destroy (client);
4117 bson_destroy (to_insert);
4118 bson_destroy (schema);
4119 bson_destroy (create_cmd);
4120 bson_destroy (create_cmd_opts);
4121 mongoc_write_concern_destroy (wc);
4122 mongoc_client_encryption_destroy (client_encryption);
4123 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
4124 mongoc_client_encryption_opts_destroy (client_encryption_opts);
4125 bson_value_destroy (&encrypted_field);
4126 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
4127 bson_value_destroy (&decrypted);
4128 bson_value_destroy (&datakey_id);
4129 mongoc_collection_destroy (unencrypted_coll);
4130 mongoc_client_destroy (unencrypted_client);
4131 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
4132
4133 mongoc_cleanup ();
4134 return exit_status;
4135 }
4136
4138 MongoDB, Inc
4139
4141 2017-present, MongoDB, Inc
4142
4143
4144
4145
41461.17.6 Jun 03, 2021 MONGOC_GUIDES(3)