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 in 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 │TIFICATEKEY‐ │ password │ any, to use to un‐ │
35 │FILEPASSWORD │ │ 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 hello responses from the servers, they update the shared view
833 of the server topology. Additional monitoring threads and connections
834 are created as new servers are discovered. Monitoring threads are ter‐
835 minated 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:
1102 mongoc_cursor_set_max_await_time_ms.
1103
1104
1106 This tutorial explains how to take advantage of MongoDB C driver bulk
1107 write operation features. Executing write operations in batches reduces
1108 the number of network round trips, increasing write throughput.
1109
1110 Bulk Insert
1111 First we need to fetch a bulk operation handle from the mongoc_collec‐
1112 tion_t.
1113
1114 mongoc_bulk_operation_t *bulk =
1115 mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1116
1117 We can now start inserting documents to the bulk operation. These will
1118 be buffered until we execute the operation.
1119
1120 The bulk operation will coalesce insertions as a single batch for each
1121 consecutive call to mongoc_bulk_operation_insert(). This creates a
1122 pipelined effect when possible.
1123
1124 To execute the bulk operation and receive the result we call mon‐
1125 goc_bulk_operation_execute().
1126
1127 bulk1.c
1128
1129 #include <assert.h>
1130 #include <mongoc/mongoc.h>
1131 #include <stdio.h>
1132
1133 static void
1134 bulk1 (mongoc_collection_t *collection)
1135 {
1136 mongoc_bulk_operation_t *bulk;
1137 bson_error_t error;
1138 bson_t *doc;
1139 bson_t reply;
1140 char *str;
1141 bool ret;
1142 int i;
1143
1144 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1145
1146 for (i = 0; i < 10000; i++) {
1147 doc = BCON_NEW ("i", BCON_INT32 (i));
1148 mongoc_bulk_operation_insert (bulk, doc);
1149 bson_destroy (doc);
1150 }
1151
1152 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1153
1154 str = bson_as_canonical_extended_json (&reply, NULL);
1155 printf ("%s\n", str);
1156 bson_free (str);
1157
1158 if (!ret) {
1159 fprintf (stderr, "Error: %s\n", error.message);
1160 }
1161
1162 bson_destroy (&reply);
1163 mongoc_bulk_operation_destroy (bulk);
1164 }
1165
1166 int
1167 main (int argc, char *argv[])
1168 {
1169 mongoc_client_t *client;
1170 mongoc_collection_t *collection;
1171 const char *uri_string = "mongodb://localhost/?appname=bulk1-example";
1172 mongoc_uri_t *uri;
1173 bson_error_t error;
1174
1175 mongoc_init ();
1176
1177 uri = mongoc_uri_new_with_error (uri_string, &error);
1178 if (!uri) {
1179 fprintf (stderr,
1180 "failed to parse URI: %s\n"
1181 "error message: %s\n",
1182 uri_string,
1183 error.message);
1184 return EXIT_FAILURE;
1185 }
1186
1187 client = mongoc_client_new_from_uri (uri);
1188 if (!client) {
1189 return EXIT_FAILURE;
1190 }
1191
1192 mongoc_client_set_error_api (client, 2);
1193 collection = mongoc_client_get_collection (client, "test", "test");
1194
1195 bulk1 (collection);
1196
1197 mongoc_uri_destroy (uri);
1198 mongoc_collection_destroy (collection);
1199 mongoc_client_destroy (client);
1200
1201 mongoc_cleanup ();
1202
1203 return EXIT_SUCCESS;
1204 }
1205
1206
1207 Example reply document:
1208
1209 {"nInserted" : 10000,
1210 "nMatched" : 0,
1211 "nModified" : 0,
1212 "nRemoved" : 0,
1213 "nUpserted" : 0,
1214 "writeErrors" : []
1215 "writeConcernErrors" : [] }
1216
1217 Mixed Bulk Write Operations
1218 MongoDB C driver also supports executing mixed bulk write operations. A
1219 batch of insert, update, and remove operations can be executed together
1220 using the bulk write operations API.
1221
1222 Ordered Bulk Write Operations
1223 Ordered bulk write operations are batched and sent to the server in the
1224 order provided for serial execution. The reply document describes the
1225 type and count of operations performed.
1226
1227 bulk2.c
1228
1229 #include <assert.h>
1230 #include <mongoc/mongoc.h>
1231 #include <stdio.h>
1232
1233 static void
1234 bulk2 (mongoc_collection_t *collection)
1235 {
1236 mongoc_bulk_operation_t *bulk;
1237 bson_error_t error;
1238 bson_t *query;
1239 bson_t *doc;
1240 bson_t *opts;
1241 bson_t reply;
1242 char *str;
1243 bool ret;
1244 int i;
1245
1246 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1247
1248 /* Remove everything */
1249 query = bson_new ();
1250 mongoc_bulk_operation_remove (bulk, query);
1251 bson_destroy (query);
1252
1253 /* Add a few documents */
1254 for (i = 1; i < 4; i++) {
1255 doc = BCON_NEW ("_id", BCON_INT32 (i));
1256 mongoc_bulk_operation_insert (bulk, doc);
1257 bson_destroy (doc);
1258 }
1259
1260 /* {_id: 1} => {$set: {foo: "bar"}} */
1261 query = BCON_NEW ("_id", BCON_INT32 (1));
1262 doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}");
1263 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, NULL, &error);
1264 bson_destroy (query);
1265 bson_destroy (doc);
1266
1267 /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */
1268 opts = BCON_NEW ("upsert", BCON_BOOL (true));
1269 query = BCON_NEW ("_id", BCON_INT32 (4));
1270 doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}");
1271 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, opts, &error);
1272 bson_destroy (query);
1273 bson_destroy (doc);
1274 bson_destroy (opts);
1275
1276 /* replace {j:1} with {j:2} */
1277 query = BCON_NEW ("j", BCON_INT32 (1));
1278 doc = BCON_NEW ("j", BCON_INT32 (2));
1279 mongoc_bulk_operation_replace_one_with_opts (bulk, query, doc, NULL, &error);
1280 bson_destroy (query);
1281 bson_destroy (doc);
1282
1283 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1284
1285 str = bson_as_canonical_extended_json (&reply, NULL);
1286 printf ("%s\n", str);
1287 bson_free (str);
1288
1289 if (!ret) {
1290 printf ("Error: %s\n", error.message);
1291 }
1292
1293 bson_destroy (&reply);
1294 mongoc_bulk_operation_destroy (bulk);
1295 }
1296
1297 int
1298 main (int argc, char *argv[])
1299 {
1300 mongoc_client_t *client;
1301 mongoc_collection_t *collection;
1302 const char *uri_string = "mongodb://localhost/?appname=bulk2-example";
1303 mongoc_uri_t *uri;
1304 bson_error_t error;
1305
1306 mongoc_init ();
1307
1308 uri = mongoc_uri_new_with_error (uri_string, &error);
1309 if (!uri) {
1310 fprintf (stderr,
1311 "failed to parse URI: %s\n"
1312 "error message: %s\n",
1313 uri_string,
1314 error.message);
1315 return EXIT_FAILURE;
1316 }
1317
1318 client = mongoc_client_new_from_uri (uri);
1319 if (!client) {
1320 return EXIT_FAILURE;
1321 }
1322
1323 mongoc_client_set_error_api (client, 2);
1324 collection = mongoc_client_get_collection (client, "test", "test");
1325
1326 bulk2 (collection);
1327
1328 mongoc_uri_destroy (uri);
1329 mongoc_collection_destroy (collection);
1330 mongoc_client_destroy (client);
1331
1332 mongoc_cleanup ();
1333
1334 return EXIT_SUCCESS;
1335 }
1336
1337
1338 Example reply document:
1339
1340 { "nInserted" : 3,
1341 "nMatched" : 2,
1342 "nModified" : 2,
1343 "nRemoved" : 10000,
1344 "nUpserted" : 1,
1345 "upserted" : [{"index" : 5, "_id" : 4}],
1346 "writeErrors" : []
1347 "writeConcernErrors" : [] }
1348
1349 The index field in the upserted array is the 0-based index of the up‐
1350 sert operation; in this example, the sixth operation of the overall
1351 bulk operation was an upsert, so its index is 5.
1352
1353 Unordered Bulk Write Operations
1354 Unordered bulk write operations are batched and sent to the server in
1355 arbitrary order where they may be executed in parallel. Any errors that
1356 occur are reported after all operations are attempted.
1357
1358 In the next example the first and third operations fail due to the
1359 unique constraint on _id. Since we are doing unordered execution the
1360 second and fourth operations succeed.
1361
1362 bulk3.c
1363
1364 #include <assert.h>
1365 #include <mongoc/mongoc.h>
1366 #include <stdio.h>
1367
1368 static void
1369 bulk3 (mongoc_collection_t *collection)
1370 {
1371 bson_t opts = BSON_INITIALIZER;
1372 mongoc_bulk_operation_t *bulk;
1373 bson_error_t error;
1374 bson_t *query;
1375 bson_t *doc;
1376 bson_t reply;
1377 char *str;
1378 bool ret;
1379
1380 /* false indicates unordered */
1381 BSON_APPEND_BOOL (&opts, "ordered", false);
1382 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1383 bson_destroy (&opts);
1384
1385 /* Add a document */
1386 doc = BCON_NEW ("_id", BCON_INT32 (1));
1387 mongoc_bulk_operation_insert (bulk, doc);
1388 bson_destroy (doc);
1389
1390 /* remove {_id: 2} */
1391 query = BCON_NEW ("_id", BCON_INT32 (2));
1392 mongoc_bulk_operation_remove_one (bulk, query);
1393 bson_destroy (query);
1394
1395 /* insert {_id: 3} */
1396 doc = BCON_NEW ("_id", BCON_INT32 (3));
1397 mongoc_bulk_operation_insert (bulk, doc);
1398 bson_destroy (doc);
1399
1400 /* replace {_id:4} {'i': 1} */
1401 query = BCON_NEW ("_id", BCON_INT32 (4));
1402 doc = BCON_NEW ("i", BCON_INT32 (1));
1403 mongoc_bulk_operation_replace_one (bulk, query, doc, false);
1404 bson_destroy (query);
1405 bson_destroy (doc);
1406
1407 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1408
1409 str = bson_as_canonical_extended_json (&reply, NULL);
1410 printf ("%s\n", str);
1411 bson_free (str);
1412
1413 if (!ret) {
1414 printf ("Error: %s\n", error.message);
1415 }
1416
1417 bson_destroy (&reply);
1418 mongoc_bulk_operation_destroy (bulk);
1419 bson_destroy (&opts);
1420 }
1421
1422 int
1423 main (int argc, char *argv[])
1424 {
1425 mongoc_client_t *client;
1426 mongoc_collection_t *collection;
1427 const char *uri_string = "mongodb://localhost/?appname=bulk3-example";
1428 mongoc_uri_t *uri;
1429 bson_error_t error;
1430
1431 mongoc_init ();
1432
1433 uri = mongoc_uri_new_with_error (uri_string, &error);
1434 if (!uri) {
1435 fprintf (stderr,
1436 "failed to parse URI: %s\n"
1437 "error message: %s\n",
1438 uri_string,
1439 error.message);
1440 return EXIT_FAILURE;
1441 }
1442
1443 client = mongoc_client_new_from_uri (uri);
1444 if (!client) {
1445 return EXIT_FAILURE;
1446 }
1447
1448 mongoc_client_set_error_api (client, 2);
1449 collection = mongoc_client_get_collection (client, "test", "test");
1450
1451 bulk3 (collection);
1452
1453 mongoc_uri_destroy (uri);
1454 mongoc_collection_destroy (collection);
1455 mongoc_client_destroy (client);
1456
1457 mongoc_cleanup ();
1458
1459 return EXIT_SUCCESS;
1460 }
1461
1462
1463 Example reply document:
1464
1465 { "nInserted" : 0,
1466 "nMatched" : 1,
1467 "nModified" : 1,
1468 "nRemoved" : 1,
1469 "nUpserted" : 0,
1470 "writeErrors" : [
1471 { "index" : 0,
1472 "code" : 11000,
1473 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" },
1474 { "index" : 2,
1475 "code" : 11000,
1476 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ],
1477 "writeConcernErrors" : [] }
1478
1479 Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }
1480
1481 The bson_error_t domain is MONGOC_ERROR_COMMAND and its code is 11000.
1482
1483 Bulk Operation Bypassing Document Validation
1484 This feature is only available when using MongoDB 3.2 and later.
1485
1486 By default bulk operations are validated against the schema, if any is
1487 defined. In certain cases however it may be necessary to bypass the
1488 document validation.
1489
1490 bulk5.c
1491
1492 #include <assert.h>
1493 #include <mongoc/mongoc.h>
1494 #include <stdio.h>
1495
1496 static void
1497 bulk5_fail (mongoc_collection_t *collection)
1498 {
1499 mongoc_bulk_operation_t *bulk;
1500 bson_error_t error;
1501 bson_t *doc;
1502 bson_t reply;
1503 char *str;
1504 bool ret;
1505
1506 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1507
1508 /* Two inserts */
1509 doc = BCON_NEW ("_id", BCON_INT32 (31));
1510 mongoc_bulk_operation_insert (bulk, doc);
1511 bson_destroy (doc);
1512
1513 doc = BCON_NEW ("_id", BCON_INT32 (32));
1514 mongoc_bulk_operation_insert (bulk, doc);
1515 bson_destroy (doc);
1516
1517 /* The above documents do not comply to the schema validation rules
1518 * we created previously, so this will result in an error */
1519 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1520
1521 str = bson_as_canonical_extended_json (&reply, NULL);
1522 printf ("%s\n", str);
1523 bson_free (str);
1524
1525 if (!ret) {
1526 printf ("Error: %s\n", error.message);
1527 }
1528
1529 bson_destroy (&reply);
1530 mongoc_bulk_operation_destroy (bulk);
1531 }
1532
1533 static void
1534 bulk5_success (mongoc_collection_t *collection)
1535 {
1536 mongoc_bulk_operation_t *bulk;
1537 bson_error_t error;
1538 bson_t *doc;
1539 bson_t reply;
1540 char *str;
1541 bool ret;
1542
1543 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1544
1545 /* Allow this document to bypass document validation.
1546 * NOTE: When authentication is enabled, the authenticated user must have
1547 * either the "dbadmin" or "restore" roles to bypass document validation */
1548 mongoc_bulk_operation_set_bypass_document_validation (bulk, true);
1549
1550 /* Two inserts */
1551 doc = BCON_NEW ("_id", BCON_INT32 (31));
1552 mongoc_bulk_operation_insert (bulk, doc);
1553 bson_destroy (doc);
1554
1555 doc = BCON_NEW ("_id", BCON_INT32 (32));
1556 mongoc_bulk_operation_insert (bulk, doc);
1557 bson_destroy (doc);
1558
1559 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1560
1561 str = bson_as_canonical_extended_json (&reply, NULL);
1562 printf ("%s\n", str);
1563 bson_free (str);
1564
1565 if (!ret) {
1566 printf ("Error: %s\n", error.message);
1567 }
1568
1569 bson_destroy (&reply);
1570 mongoc_bulk_operation_destroy (bulk);
1571 }
1572
1573 int
1574 main (int argc, char *argv[])
1575 {
1576 bson_t *options;
1577 bson_error_t error;
1578 mongoc_client_t *client;
1579 mongoc_collection_t *collection;
1580 mongoc_database_t *database;
1581 const char *uri_string = "mongodb://localhost/?appname=bulk5-example";
1582 mongoc_uri_t *uri;
1583
1584 mongoc_init ();
1585
1586 uri = mongoc_uri_new_with_error (uri_string, &error);
1587 if (!uri) {
1588 fprintf (stderr,
1589 "failed to parse URI: %s\n"
1590 "error message: %s\n",
1591 uri_string,
1592 error.message);
1593 return EXIT_FAILURE;
1594 }
1595
1596 client = mongoc_client_new_from_uri (uri);
1597 if (!client) {
1598 return EXIT_FAILURE;
1599 }
1600
1601 mongoc_client_set_error_api (client, 2);
1602 database = mongoc_client_get_database (client, "testasdf");
1603
1604 /* Create schema validator */
1605 options = BCON_NEW (
1606 "validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}");
1607 collection =
1608 mongoc_database_create_collection (database, "collname", options, &error);
1609
1610 if (collection) {
1611 bulk5_fail (collection);
1612 bulk5_success (collection);
1613 mongoc_collection_destroy (collection);
1614 } else {
1615 fprintf (stderr, "Couldn't create collection: '%s'\n", error.message);
1616 }
1617
1618 bson_free (options);
1619 mongoc_uri_destroy (uri);
1620 mongoc_database_destroy (database);
1621 mongoc_client_destroy (client);
1622
1623 mongoc_cleanup ();
1624
1625 return EXIT_SUCCESS;
1626 }
1627
1628
1629 Running the above example will result in:
1630
1631 { "nInserted" : 0,
1632 "nMatched" : 0,
1633 "nModified" : 0,
1634 "nRemoved" : 0,
1635 "nUpserted" : 0,
1636 "writeErrors" : [
1637 { "index" : 0,
1638 "code" : 121,
1639 "errmsg" : "Document failed validation" } ] }
1640
1641 Error: Document failed validation
1642
1643 { "nInserted" : 2,
1644 "nMatched" : 0,
1645 "nModified" : 0,
1646 "nRemoved" : 0,
1647 "nUpserted" : 0,
1648 "writeErrors" : [] }
1649
1650 The bson_error_t domain is MONGOC_ERROR_COMMAND.
1651
1652 Bulk Operation Write Concerns
1653 By default bulk operations are executed with the write_concern of the
1654 collection they are executed against. A custom write concern can be
1655 passed to the mongoc_collection_create_bulk_operation_with_opts()
1656 method. Write concern errors (e.g. wtimeout) will be reported after all
1657 operations are attempted, regardless of execution order.
1658
1659 bulk4.c
1660
1661 #include <assert.h>
1662 #include <mongoc/mongoc.h>
1663 #include <stdio.h>
1664
1665 static void
1666 bulk4 (mongoc_collection_t *collection)
1667 {
1668 bson_t opts = BSON_INITIALIZER;
1669 mongoc_write_concern_t *wc;
1670 mongoc_bulk_operation_t *bulk;
1671 bson_error_t error;
1672 bson_t *doc;
1673 bson_t reply;
1674 char *str;
1675 bool ret;
1676
1677 wc = mongoc_write_concern_new ();
1678 mongoc_write_concern_set_w (wc, 4);
1679 mongoc_write_concern_set_wtimeout_int64 (wc, 100); /* milliseconds */
1680 mongoc_write_concern_append (wc, &opts);
1681
1682 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1683
1684 /* Two inserts */
1685 doc = BCON_NEW ("_id", BCON_INT32 (10));
1686 mongoc_bulk_operation_insert (bulk, doc);
1687 bson_destroy (doc);
1688
1689 doc = BCON_NEW ("_id", BCON_INT32 (11));
1690 mongoc_bulk_operation_insert (bulk, doc);
1691 bson_destroy (doc);
1692
1693 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1694
1695 str = bson_as_canonical_extended_json (&reply, NULL);
1696 printf ("%s\n", str);
1697 bson_free (str);
1698
1699 if (!ret) {
1700 printf ("Error: %s\n", error.message);
1701 }
1702
1703 bson_destroy (&reply);
1704 mongoc_bulk_operation_destroy (bulk);
1705 mongoc_write_concern_destroy (wc);
1706 bson_destroy (&opts);
1707 }
1708
1709 int
1710 main (int argc, char *argv[])
1711 {
1712 mongoc_client_t *client;
1713 mongoc_collection_t *collection;
1714 const char *uri_string = "mongodb://localhost/?appname=bulk4-example";
1715 mongoc_uri_t *uri;
1716 bson_error_t error;
1717
1718 mongoc_init ();
1719
1720 uri = mongoc_uri_new_with_error (uri_string, &error);
1721 if (!uri) {
1722 fprintf (stderr,
1723 "failed to parse URI: %s\n"
1724 "error message: %s\n",
1725 uri_string,
1726 error.message);
1727 return EXIT_FAILURE;
1728 }
1729
1730 client = mongoc_client_new_from_uri (uri);
1731 if (!client) {
1732 return EXIT_FAILURE;
1733 }
1734
1735 mongoc_client_set_error_api (client, 2);
1736 collection = mongoc_client_get_collection (client, "test", "test");
1737
1738 bulk4 (collection);
1739
1740 mongoc_uri_destroy (uri);
1741 mongoc_collection_destroy (collection);
1742 mongoc_client_destroy (client);
1743
1744 mongoc_cleanup ();
1745
1746 return EXIT_SUCCESS;
1747 }
1748
1749
1750 Example reply document and error message:
1751
1752 { "nInserted" : 2,
1753 "nMatched" : 0,
1754 "nModified" : 0,
1755 "nRemoved" : 0,
1756 "nUpserted" : 0,
1757 "writeErrors" : [],
1758 "writeConcernErrors" : [
1759 { "code" : 64,
1760 "errmsg" : "waiting for replication timed out" }
1761 ] }
1762
1763 Error: waiting for replication timed out
1764
1765 The bson_error_t domain is MONGOC_ERROR_WRITE_CONCERN if there are
1766 write concern errors and no write errors. Write errors indicate failed
1767 operations, so they take precedence over write concern errors, which
1768 mean merely that the write concern is not satisfied yet.
1769
1770 Setting Collation Order
1771 This feature is only available when using MongoDB 3.4 and later.
1772
1773 bulk-collation.c
1774
1775 #include <mongoc/mongoc.h>
1776 #include <stdio.h>
1777
1778 static void
1779 bulk_collation (mongoc_collection_t *collection)
1780 {
1781 mongoc_bulk_operation_t *bulk;
1782 bson_t *opts;
1783 bson_t *doc;
1784 bson_t *selector;
1785 bson_t *update;
1786 bson_error_t error;
1787 bson_t reply;
1788 char *str;
1789 uint32_t ret;
1790
1791 /* insert {_id: "one"} and {_id: "One"} */
1792 bulk = mongoc_collection_create_bulk_operation_with_opts (
1793 collection, NULL);
1794 doc = BCON_NEW ("_id", BCON_UTF8 ("one"));
1795 mongoc_bulk_operation_insert (bulk, doc);
1796 bson_destroy (doc);
1797
1798 doc = BCON_NEW ("_id", BCON_UTF8 ("One"));
1799 mongoc_bulk_operation_insert (bulk, doc);
1800 bson_destroy (doc);
1801
1802 /* "One" normally sorts before "one"; make "one" come first */
1803 opts = BCON_NEW ("collation",
1804 "{",
1805 "locale",
1806 BCON_UTF8 ("en_US"),
1807 "caseFirst",
1808 BCON_UTF8 ("lower"),
1809 "}");
1810
1811 /* set x=1 on the document with _id "One", which now sorts after "one" */
1812 update = BCON_NEW ("$set", "{", "x", BCON_INT64 (1), "}");
1813 selector = BCON_NEW ("_id", "{", "$gt", BCON_UTF8 ("one"), "}");
1814 mongoc_bulk_operation_update_one_with_opts (
1815 bulk, selector, update, opts, &error);
1816
1817 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1818
1819 str = bson_as_canonical_extended_json (&reply, NULL);
1820 printf ("%s\n", str);
1821 bson_free (str);
1822
1823 if (!ret) {
1824 printf ("Error: %s\n", error.message);
1825 }
1826
1827 bson_destroy (&reply);
1828 bson_destroy (update);
1829 bson_destroy (selector);
1830 bson_destroy (opts);
1831 mongoc_bulk_operation_destroy (bulk);
1832 }
1833
1834 int
1835 main (int argc, char *argv[])
1836 {
1837 mongoc_client_t *client;
1838 mongoc_collection_t *collection;
1839 const char *uri_string = "mongodb://localhost/?appname=bulk-collation";
1840 mongoc_uri_t *uri;
1841 bson_error_t error;
1842
1843 mongoc_init ();
1844
1845 uri = mongoc_uri_new_with_error (uri_string, &error);
1846 if (!uri) {
1847 fprintf (stderr,
1848 "failed to parse URI: %s\n"
1849 "error message: %s\n",
1850 uri_string,
1851 error.message);
1852 return EXIT_FAILURE;
1853 }
1854
1855 client = mongoc_client_new_from_uri (uri);
1856 if (!client) {
1857 return EXIT_FAILURE;
1858 }
1859
1860 mongoc_client_set_error_api (client, 2);
1861 collection = mongoc_client_get_collection (client, "db", "collection");
1862 bulk_collation (collection);
1863
1864 mongoc_uri_destroy (uri);
1865 mongoc_collection_destroy (collection);
1866 mongoc_client_destroy (client);
1867
1868 mongoc_cleanup ();
1869
1870 return EXIT_SUCCESS;
1871 }
1872
1873
1874 Running the above example will result in:
1875
1876 { "nInserted" : 2,
1877 "nMatched" : 1,
1878 "nModified" : 1,
1879 "nRemoved" : 0,
1880 "nUpserted" : 0,
1881 "writeErrors" : [ ]
1882 }
1883
1884 Unacknowledged Bulk Writes
1885 Set "w" to zero for an unacknowledged write. The driver sends unac‐
1886 knowledged writes using the legacy opcodes OP_INSERT, OP_UPDATE, and
1887 OP_DELETE.
1888
1889 bulk6.c
1890
1891 #include <mongoc/mongoc.h>
1892 #include <stdio.h>
1893
1894 static void
1895 bulk6 (mongoc_collection_t *collection)
1896 {
1897 bson_t opts = BSON_INITIALIZER;
1898 mongoc_write_concern_t *wc;
1899 mongoc_bulk_operation_t *bulk;
1900 bson_error_t error;
1901 bson_t *doc;
1902 bson_t *selector;
1903 bson_t reply;
1904 char *str;
1905 bool ret;
1906
1907 wc = mongoc_write_concern_new ();
1908 mongoc_write_concern_set_w (wc, 0);
1909 mongoc_write_concern_append (wc, &opts);
1910
1911 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1912
1913 doc = BCON_NEW ("_id", BCON_INT32 (10));
1914 mongoc_bulk_operation_insert (bulk, doc);
1915 bson_destroy (doc);
1916
1917 selector = BCON_NEW ("_id", BCON_INT32 (11));
1918 mongoc_bulk_operation_remove_one (bulk, selector);
1919 bson_destroy (selector);
1920
1921 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1922
1923 str = bson_as_canonical_extended_json (&reply, NULL);
1924 printf ("%s\n", str);
1925 bson_free (str);
1926
1927 if (!ret) {
1928 printf ("Error: %s\n", error.message);
1929 }
1930
1931 bson_destroy (&reply);
1932 mongoc_bulk_operation_destroy (bulk);
1933 mongoc_write_concern_destroy (wc);
1934 bson_destroy (&opts);
1935 }
1936
1937 int
1938 main (int argc, char *argv[])
1939 {
1940 mongoc_client_t *client;
1941 mongoc_collection_t *collection;
1942 const char *uri_string = "mongodb://localhost/?appname=bulk6-example";
1943 mongoc_uri_t *uri;
1944 bson_error_t error;
1945
1946 mongoc_init ();
1947
1948 uri = mongoc_uri_new_with_error (uri_string, &error);
1949 if (!uri) {
1950 fprintf (stderr,
1951 "failed to parse URI: %s\n"
1952 "error message: %s\n",
1953 uri_string,
1954 error.message);
1955 return EXIT_FAILURE;
1956 }
1957
1958 client = mongoc_client_new_from_uri (uri);
1959 if (!client) {
1960 return EXIT_FAILURE;
1961 }
1962
1963 mongoc_client_set_error_api (client, 2);
1964 collection = mongoc_client_get_collection (client, "test", "test");
1965
1966 bulk6 (collection);
1967
1968 mongoc_uri_destroy (uri);
1969 mongoc_collection_destroy (collection);
1970 mongoc_client_destroy (client);
1971
1972 mongoc_cleanup ();
1973
1974 return EXIT_SUCCESS;
1975 }
1976
1977
1978 The reply document is empty:
1979
1980 { }
1981
1982 Further Reading
1983 See the Driver Bulk API Spec, which describes bulk write operations for
1984 all MongoDB drivers.
1985
1987 This document provides a number of practical examples that display the
1988 capabilities of the aggregation framework.
1989
1990 The Aggregations using the Zip Codes Data Set examples uses a publicly
1991 available data set of all zipcodes and populations in the United
1992 States. These data are available at: zips.json.
1993
1994 Requirements
1995 Let's check if everything is installed.
1996
1997 Use the following command to load zips.json data set into mongod in‐
1998 stance:
1999
2000 $ mongoimport --drop -d test -c zipcodes zips.json
2001
2002 Let's use the MongoDB shell to verify that everything was imported suc‐
2003 cessfully.
2004
2005 $ mongo test
2006 connecting to: test
2007 > db.zipcodes.count()
2008 29467
2009 > db.zipcodes.findOne()
2010 {
2011 "_id" : "35004",
2012 "city" : "ACMAR",
2013 "loc" : [
2014 -86.51557,
2015 33.584132
2016 ],
2017 "pop" : 6055,
2018 "state" : "AL"
2019 }
2020
2021 Aggregations using the Zip Codes Data Set
2022 Each document in this collection has the following form:
2023
2024 {
2025 "_id" : "35004",
2026 "city" : "Acmar",
2027 "state" : "AL",
2028 "pop" : 6055,
2029 "loc" : [-86.51557, 33.584132]
2030 }
2031
2032 In these documents:
2033
2034 • The _id field holds the zipcode as a string.
2035
2036 • The city field holds the city name.
2037
2038 • The state field holds the two letter state abbreviation.
2039
2040 • The pop field holds the population.
2041
2042 • The loc field holds the location as a [latitude, longitude] array.
2043
2044 States with Populations Over 10 Million
2045 To get all states with a population greater than 10 million, use the
2046 following aggregation pipeline:
2047
2048 aggregation1.c
2049
2050 #include <mongoc/mongoc.h>
2051 #include <stdio.h>
2052
2053 static void
2054 print_pipeline (mongoc_collection_t *collection)
2055 {
2056 mongoc_cursor_t *cursor;
2057 bson_error_t error;
2058 const bson_t *doc;
2059 bson_t *pipeline;
2060 char *str;
2061
2062 pipeline = BCON_NEW ("pipeline",
2063 "[",
2064 "{",
2065 "$group",
2066 "{",
2067 "_id",
2068 "$state",
2069 "total_pop",
2070 "{",
2071 "$sum",
2072 "$pop",
2073 "}",
2074 "}",
2075 "}",
2076 "{",
2077 "$match",
2078 "{",
2079 "total_pop",
2080 "{",
2081 "$gte",
2082 BCON_INT32 (10000000),
2083 "}",
2084 "}",
2085 "}",
2086 "]");
2087
2088 cursor = mongoc_collection_aggregate (
2089 collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL);
2090
2091 while (mongoc_cursor_next (cursor, &doc)) {
2092 str = bson_as_canonical_extended_json (doc, NULL);
2093 printf ("%s\n", str);
2094 bson_free (str);
2095 }
2096
2097 if (mongoc_cursor_error (cursor, &error)) {
2098 fprintf (stderr, "Cursor Failure: %s\n", error.message);
2099 }
2100
2101 mongoc_cursor_destroy (cursor);
2102 bson_destroy (pipeline);
2103 }
2104
2105 int
2106 main (int argc, char *argv[])
2107 {
2108 mongoc_client_t *client;
2109 mongoc_collection_t *collection;
2110 const char *uri_string =
2111 "mongodb://localhost:27017/?appname=aggregation-example";
2112 mongoc_uri_t *uri;
2113 bson_error_t error;
2114
2115 mongoc_init ();
2116
2117 uri = mongoc_uri_new_with_error (uri_string, &error);
2118 if (!uri) {
2119 fprintf (stderr,
2120 "failed to parse URI: %s\n"
2121 "error message: %s\n",
2122 uri_string,
2123 error.message);
2124 return EXIT_FAILURE;
2125 }
2126
2127 client = mongoc_client_new_from_uri (uri);
2128 if (!client) {
2129 return EXIT_FAILURE;
2130 }
2131
2132 mongoc_client_set_error_api (client, 2);
2133 collection = mongoc_client_get_collection (client, "test", "zipcodes");
2134
2135 print_pipeline (collection);
2136
2137 mongoc_uri_destroy (uri);
2138 mongoc_collection_destroy (collection);
2139 mongoc_client_destroy (client);
2140
2141 mongoc_cleanup ();
2142
2143 return EXIT_SUCCESS;
2144 }
2145
2146
2147 You should see a result like the following:
2148
2149 { "_id" : "PA", "total_pop" : 11881643 }
2150 { "_id" : "OH", "total_pop" : 10847115 }
2151 { "_id" : "NY", "total_pop" : 17990455 }
2152 { "_id" : "FL", "total_pop" : 12937284 }
2153 { "_id" : "TX", "total_pop" : 16986510 }
2154 { "_id" : "IL", "total_pop" : 11430472 }
2155 { "_id" : "CA", "total_pop" : 29760021 }
2156
2157 The above aggregation pipeline is build from two pipeline operators:
2158 $group and $match.
2159
2160 The $group pipeline operator requires _id field where we specify group‐
2161 ing; remaining fields specify how to generate composite value and must
2162 use one of the group aggregation functions: $addToSet, $first, $last,
2163 $max, $min, $avg, $push, $sum. The $match pipeline operator syntax is
2164 the same as the read operation query syntax.
2165
2166 The $group process reads all documents and for each state it creates a
2167 separate document, for example:
2168
2169 { "_id" : "WA", "total_pop" : 4866692 }
2170
2171 The total_pop field uses the $sum aggregation function to sum the val‐
2172 ues of all pop fields in the source documents.
2173
2174 Documents created by $group are piped to the $match pipeline operator.
2175 It returns the documents with the value of total_pop field greater than
2176 or equal to 10 million.
2177
2178 Average City Population by State
2179 To get the first three states with the greatest average population per
2180 city, use the following aggregation:
2181
2182 pipeline = BCON_NEW ("pipeline", "[",
2183 "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}",
2184 "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}",
2185 "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}",
2186 "{", "$limit", BCON_INT32 (3) "}",
2187 "]");
2188
2189 This aggregate pipeline produces:
2190
2191 { "_id" : "DC", "avg_city_pop" : 303450.0 }
2192 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2193 { "_id" : "CA", "avg_city_pop" : 27735.341099720412 }
2194
2195 The above aggregation pipeline is build from three pipeline operators:
2196 $group, $sort and $limit.
2197
2198 The first $group operator creates the following documents:
2199
2200 { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 }
2201
2202 Note, that the $group operator can't use nested documents except the
2203 _id field.
2204
2205 The second $group uses these documents to create the following docu‐
2206 ments:
2207
2208 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2209
2210 These documents are sorted by the avg_city_pop field in descending or‐
2211 der. Finally, the $limit pipeline operator returns the first 3 docu‐
2212 ments from the sorted set.
2213
2215 This document provides some practical, simple, examples to demonstrate
2216 the distinct and mapReduce commands.
2217
2218 Setup
2219 First we'll write some code to insert sample data:
2220
2221 doc-common-insert.c
2222
2223 /* Don't try to compile this file on its own. It's meant to be #included
2224 by example code */
2225
2226 /* Insert some sample data */
2227 bool
2228 insert_data (mongoc_collection_t *collection)
2229 {
2230 mongoc_bulk_operation_t *bulk;
2231 enum N { ndocs = 4 };
2232 bson_t *docs[ndocs];
2233 bson_error_t error;
2234 int i = 0;
2235 bool ret;
2236
2237 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
2238
2239 docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
2240 docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
2241 docs[2] = BCON_NEW (
2242 "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
2243 docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
2244
2245 for (i = 0; i < ndocs; i++) {
2246 mongoc_bulk_operation_insert (bulk, docs[i]);
2247 bson_destroy (docs[i]);
2248 docs[i] = NULL;
2249 }
2250
2251 ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
2252
2253 if (!ret) {
2254 fprintf (stderr, "Error inserting data: %s\n", error.message);
2255 }
2256
2257 mongoc_bulk_operation_destroy (bulk);
2258 return ret;
2259 }
2260
2261 /* A helper which we'll use a lot later on */
2262 void
2263 print_res (const bson_t *reply)
2264 {
2265 char *str;
2266 BSON_ASSERT (reply);
2267 str = bson_as_canonical_extended_json (reply, NULL);
2268 printf ("%s\n", str);
2269 bson_free (str);
2270 }
2271
2272
2273 distinct command
2274 This is how to use the distinct command to get the distinct values of x
2275 which are greater than 1:
2276
2277 distinct.c
2278
2279 bool
2280 distinct (mongoc_database_t *database)
2281 {
2282 bson_t *command;
2283 bson_t reply;
2284 bson_error_t error;
2285 bool res;
2286 bson_iter_t iter;
2287 bson_iter_t array_iter;
2288 double val;
2289
2290 command = BCON_NEW ("distinct",
2291 BCON_UTF8 (COLLECTION_NAME),
2292 "key",
2293 BCON_UTF8 ("x"),
2294 "query",
2295 "{",
2296 "x",
2297 "{",
2298 "$gt",
2299 BCON_DOUBLE (1.0),
2300 "}",
2301 "}");
2302 res =
2303 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2304 if (!res) {
2305 fprintf (stderr, "Error with distinct: %s\n", error.message);
2306 goto cleanup;
2307 }
2308
2309 /* Do something with reply (in this case iterate through the values) */
2310 if (!(bson_iter_init_find (&iter, &reply, "values") &&
2311 BSON_ITER_HOLDS_ARRAY (&iter) &&
2312 bson_iter_recurse (&iter, &array_iter))) {
2313 fprintf (stderr, "Couldn't extract \"values\" field from response\n");
2314 goto cleanup;
2315 }
2316
2317 while (bson_iter_next (&array_iter)) {
2318 if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) {
2319 val = bson_iter_double (&array_iter);
2320 printf ("Next double: %f\n", val);
2321 }
2322 }
2323
2324 cleanup:
2325 /* cleanup */
2326 bson_destroy (command);
2327 bson_destroy (&reply);
2328 return res;
2329 }
2330
2331
2332 mapReduce - basic example
2333 A simple example using the map reduce framework. It simply adds up the
2334 number of occurrences of each "tag".
2335
2336 First define the map and reduce functions:
2337
2338 constants.c
2339
2340 const char *const COLLECTION_NAME = "things";
2341
2342 /* Our map function just emits a single (key, 1) pair for each tag
2343 in the array: */
2344 const char *const MAPPER = "function () {"
2345 "this.tags.forEach(function(z) {"
2346 "emit(z, 1);"
2347 "});"
2348 "}";
2349
2350 /* The reduce function sums over all of the emitted values for a
2351 given key: */
2352 const char *const REDUCER = "function (key, values) {"
2353 "var total = 0;"
2354 "for (var i = 0; i < values.length; i++) {"
2355 "total += values[i];"
2356 "}"
2357 "return total;"
2358 "}";
2359 /* Note We can't just return values.length as the reduce function
2360 might be called iteratively on the results of other reduce
2361 steps. */
2362
2363
2364 Run the mapReduce command. Use the generic command helpers (e.g. mon‐
2365 goc_database_command_simple()). Do not the read command helpers (e.g.
2366 mongoc_database_read_command_with_opts()) because they are considered
2367 retryable read operations. If retryable reads are enabled, those opera‐
2368 tions will retry once on a retryable error, giving undesirable behavior
2369 for mapReduce.
2370
2371 map-reduce-basic.c
2372
2373 bool
2374 map_reduce_basic (mongoc_database_t *database)
2375 {
2376 bson_t reply;
2377 bson_t *command;
2378 bool res;
2379 bson_error_t error;
2380 mongoc_cursor_t *cursor;
2381 const bson_t *doc;
2382
2383 bool query_done = false;
2384
2385 const char *out_collection_name = "outCollection";
2386 mongoc_collection_t *out_collection;
2387
2388 /* Empty find query */
2389 bson_t find_query = BSON_INITIALIZER;
2390
2391 /* Construct the mapReduce command */
2392
2393 /* Other arguments can also be specified here, like "query" or
2394 "limit" and so on */
2395 command = BCON_NEW ("mapReduce",
2396 BCON_UTF8 (COLLECTION_NAME),
2397 "map",
2398 BCON_CODE (MAPPER),
2399 "reduce",
2400 BCON_CODE (REDUCER),
2401 "out",
2402 BCON_UTF8 (out_collection_name));
2403 res =
2404 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2405
2406 if (!res) {
2407 fprintf (stderr, "MapReduce failed: %s\n", error.message);
2408 goto cleanup;
2409 }
2410
2411 /* Do something with the reply (it doesn't contain the mapReduce results) */
2412 print_res (&reply);
2413
2414 /* Now we'll query outCollection to see what the results are */
2415 out_collection =
2416 mongoc_database_get_collection (database, out_collection_name);
2417 cursor = mongoc_collection_find_with_opts (
2418 out_collection, &find_query, NULL, NULL);
2419 query_done = true;
2420
2421 /* Do something with the results */
2422 while (mongoc_cursor_next (cursor, &doc)) {
2423 print_res (doc);
2424 }
2425
2426 if (mongoc_cursor_error (cursor, &error)) {
2427 fprintf (stderr, "ERROR: %s\n", error.message);
2428 res = false;
2429 goto cleanup;
2430 }
2431
2432 cleanup:
2433 /* cleanup */
2434 if (query_done) {
2435 mongoc_cursor_destroy (cursor);
2436 mongoc_collection_destroy (out_collection);
2437 }
2438
2439 bson_destroy (&reply);
2440 bson_destroy (command);
2441
2442 return res;
2443 }
2444
2445
2446 mapReduce - more complicated example
2447 You must have replica set running for this.
2448
2449 In this example we contact a secondary in the replica set and do an
2450 "inline" map reduce, so the results are returned immediately:
2451
2452 map-reduce-advanced.c
2453
2454 bool
2455 map_reduce_advanced (mongoc_database_t *database)
2456 {
2457 bson_t *command;
2458 bson_error_t error;
2459 bool res = true;
2460 mongoc_cursor_t *cursor;
2461 mongoc_read_prefs_t *read_pref;
2462 const bson_t *doc;
2463
2464 /* Construct the mapReduce command */
2465 /* Other arguments can also be specified here, like "query" or "limit"
2466 and so on */
2467
2468 /* Read the results inline from a secondary replica */
2469 command = BCON_NEW ("mapReduce",
2470 BCON_UTF8 (COLLECTION_NAME),
2471 "map",
2472 BCON_CODE (MAPPER),
2473 "reduce",
2474 BCON_CODE (REDUCER),
2475 "out",
2476 "{",
2477 "inline",
2478 "1",
2479 "}");
2480
2481 read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
2482 cursor = mongoc_database_command (
2483 database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref);
2484
2485 /* Do something with the results */
2486 while (mongoc_cursor_next (cursor, &doc)) {
2487 print_res (doc);
2488 }
2489
2490 if (mongoc_cursor_error (cursor, &error)) {
2491 fprintf (stderr, "ERROR: %s\n", error.message);
2492 res = false;
2493 }
2494
2495 mongoc_cursor_destroy (cursor);
2496 mongoc_read_prefs_destroy (read_pref);
2497 bson_destroy (command);
2498
2499 return res;
2500 }
2501
2502
2503 Running the Examples
2504 Here's how to run the example code
2505
2506 basic-aggregation.c
2507
2508 /*
2509 * Copyright 2016 MongoDB, Inc.
2510 *
2511 * Licensed under the Apache License, Version 2.0 (the "License");
2512 * you may not use this file except in compliance with the License.
2513 * You may obtain a copy of the License at
2514 *
2515 * http://www.apache.org/licenses/LICENSE-2.0
2516 *
2517 * Unless required by applicable law or agreed to in writing, software
2518 * distributed under the License is distributed on an "AS IS" BASIS,
2519 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2520 * See the License for the specific language governing permissions and
2521 * limitations under the License.
2522 */
2523
2524
2525 #include <mongoc/mongoc.h>
2526 #include <stdio.h>
2527
2528
2529 #include "constants.c"
2530
2531 #include "../doc-common-insert.c"
2532 #include "distinct.c"
2533 #include "map-reduce-basic.c"
2534 #include "map-reduce-advanced.c"
2535
2536
2537 int
2538 main (int argc, char *argv[])
2539 {
2540 mongoc_database_t *database = NULL;
2541 mongoc_client_t *client = NULL;
2542 mongoc_collection_t *collection = NULL;
2543 mongoc_uri_t *uri = NULL;
2544 bson_error_t error;
2545 char *host_and_port = NULL;
2546 int exit_code = EXIT_FAILURE;
2547
2548 if (argc != 2) {
2549 fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]);
2550 fprintf (stderr,
2551 "the connection string can be of the following forms:\n");
2552 fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
2553 fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
2554 fprintf (stderr,
2555 "mongodb://user:pass@localhost:27017\t"
2556 "local machine on port 27017, and authenticate with username "
2557 "user and password pass\n");
2558 return exit_code;
2559 }
2560
2561 mongoc_init ();
2562
2563 if (strncmp (argv[1], "mongodb://", 10) == 0) {
2564 host_and_port = bson_strdup (argv[1]);
2565 } else {
2566 host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
2567 }
2568
2569 uri = mongoc_uri_new_with_error (host_and_port, &error);
2570 if (!uri) {
2571 fprintf (stderr,
2572 "failed to parse URI: %s\n"
2573 "error message: %s\n",
2574 host_and_port,
2575 error.message);
2576 goto cleanup;
2577 }
2578
2579 client = mongoc_client_new_from_uri (uri);
2580 if (!client) {
2581 goto cleanup;
2582 }
2583
2584 mongoc_client_set_error_api (client, 2);
2585 database = mongoc_client_get_database (client, "test");
2586 collection = mongoc_database_get_collection (database, COLLECTION_NAME);
2587
2588 printf ("Inserting data\n");
2589 if (!insert_data (collection)) {
2590 goto cleanup;
2591 }
2592
2593 printf ("distinct\n");
2594 if (!distinct (database)) {
2595 goto cleanup;
2596 }
2597
2598 printf ("map reduce\n");
2599 if (!map_reduce_basic (database)) {
2600 goto cleanup;
2601 }
2602
2603 printf ("more complicated map reduce\n");
2604 if (!map_reduce_advanced (database)) {
2605 goto cleanup;
2606 }
2607
2608 exit_code = EXIT_SUCCESS;
2609
2610 cleanup:
2611 if (collection) {
2612 mongoc_collection_destroy (collection);
2613 }
2614
2615 if (database) {
2616 mongoc_database_destroy (database);
2617 }
2618
2619 if (client) {
2620 mongoc_client_destroy (client);
2621 }
2622
2623 if (uri) {
2624 mongoc_uri_destroy (uri);
2625 }
2626
2627 if (host_and_port) {
2628 bson_free (host_and_port);
2629 }
2630
2631 mongoc_cleanup ();
2632 return exit_code;
2633 }
2634
2635
2636 If you want to try the advanced map reduce example with a secondary,
2637 start a replica set (instructions for how to do this can be found
2638 here).
2639
2640 Otherwise, just start an instance of MongoDB:
2641
2642 $ mongod
2643
2644 Now compile and run the example program:
2645
2646 $ cd examples/basic_aggregation/
2647 $ gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0)
2648 $ ./agg-example localhost
2649
2650 Inserting data
2651 distinct
2652 Next double: 2.000000
2653 Next double: 3.000000
2654 map reduce
2655 { "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
2656 { "_id" : "cat", "value" : 63 }
2657 { "_id" : "dog", "value" : 42 }
2658 { "_id" : "mouse", "value" : 21 }
2659 more complicated map reduce
2660 { "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 }
2661
2663 Download and install libmongoc on your system, then open Visual Studio,
2664 select "File→New→Project...", and create a new Win32 Console Applica‐
2665 tion. [image]
2666
2667 Remember to switch the platform from 32-bit to 64-bit: [image]
2668
2669 Right-click on your console application in the Solution Explorer and
2670 select "Properties". Choose to edit properties for "All Configura‐
2671 tions", expand the "C/C++" options and choose "General". Add to the
2672 "Additional Include Directories" these paths:
2673
2674 C:\mongo-c-driver\include\libbson-1.0
2675 C:\mongo-c-driver\include\libmongoc-1.0
2676 [image]
2677
2678 (If you chose a different CMAKE_INSTALL_PREFIX when you ran CMake, your
2679 include paths will be different.)
2680
2681 Also in the Properties dialog, expand the "Linker" options and choose
2682 "Input", and add to the "Additional Dependencies" these libraries:
2683
2684 C:\mongo-c-driver\lib\bson-1.0.lib
2685 C:\mongo-c-driver\lib\mongoc-1.0.lib
2686 [image]
2687
2688 Adding these libraries as dependencies provides linker symbols to build
2689 your application, but to actually run it, libbson's and libmongoc's
2690 DLLs must be in your executable path. Select "Debugging" in the Proper‐
2691 ties dialog, and set the "Environment" option to:
2692
2693 PATH=c:/mongo-c-driver/bin
2694 [image]
2695
2696 Finally, include "mongoc/mongoc.h" in your project's "stdafx.h":
2697
2698 #include <mongoc/mongoc.h>
2699
2700 Static linking
2701 Following the instructions above, you have dynamically linked your ap‐
2702 plication to the libbson and libmongoc DLLs. This is usually the right
2703 choice. If you want to link statically instead, update your "Additional
2704 Dependencies" list by removing bson-1.0.lib and mongoc-1.0.lib and re‐
2705 placing them with these libraries:
2706
2707 C:\mongo-c-driver\lib\bson-static-1.0.lib
2708 C:\mongo-c-driver\lib\mongoc-static-1.0.lib
2709 ws2_32.lib
2710 Secur32.lib
2711 Crypt32.lib
2712 BCrypt.lib
2713 [image]
2714
2715 (To explain the purpose of each library: bson-static-1.0.lib and mon‐
2716 goc-static-1.0.lib are static archives of the driver code. The socket
2717 library ws2_32 is required by libbson, which uses the socket routine
2718 gethostname to help guarantee ObjectId uniqueness. The BCrypt library
2719 is used by libmongoc for TLS connections to MongoDB, and Secur32 and
2720 Crypt32 are required for enterprise authentication methods like Ker‐
2721 beros.)
2722
2723 Finally, define two preprocessor symbols before including mongoc/mon‐
2724 goc.h in your stdafx.h:
2725
2726 #define BSON_STATIC
2727 #define MONGOC_STATIC
2728 #include <mongoc/mongoc.h>
2729
2730 Making these changes to your project is only required for static link‐
2731 ing; for most people, the dynamic-linking instructions above are pre‐
2732 ferred.
2733
2734 Next Steps
2735 Now you can build and debug applications in Visual Studio that use
2736 libbson and libmongoc. Proceed to making-a-connection in the tutorial
2737 to learn how connect to MongoDB and perform operations.
2738
2740 To create indexes on a MongoDB collection, execute the createIndexes
2741 command with a command function like mongoc_database_write_com‐
2742 mand_with_opts or mongoc_collection_write_command_with_opts. See the
2743 MongoDB Manual entry for the createIndexes command for details.
2744
2745 WARNING:
2746 The commitQuorum option to the createIndexes command is only sup‐
2747 ported in MongoDB 4.4+ servers, but it is not validated in the com‐
2748 mand functions. Do not pass commitQuorum if connected to server ver‐
2749 sions less than 4.4. Using the commitQuorum option on server ver‐
2750 sions less than 4.4 may have adverse effects on index builds.
2751
2752 Example
2753 example-create-indexes.c
2754
2755 /* gcc example-create-indexes.c -o example-create-indexes $(pkg-config --cflags
2756 * --libs libmongoc-1.0) */
2757
2758 /* ./example-create-indexes [CONNECTION_STRING [COLLECTION_NAME]] */
2759
2760 #include <mongoc/mongoc.h>
2761 #include <stdio.h>
2762 #include <stdlib.h>
2763
2764 int
2765 main (int argc, char *argv[])
2766 {
2767 mongoc_client_t *client;
2768 const char *uri_string =
2769 "mongodb://127.0.0.1/?appname=create-indexes-example";
2770 mongoc_uri_t *uri;
2771 mongoc_database_t *db;
2772 const char *collection_name = "test";
2773 bson_t keys;
2774 char *index_name;
2775 bson_t *create_indexes;
2776 bson_t reply;
2777 char *reply_str;
2778 bson_error_t error;
2779 bool r;
2780
2781 mongoc_init ();
2782
2783 if (argc > 1) {
2784 uri_string = argv[1];
2785 }
2786
2787 if (argc > 2) {
2788 collection_name = argv[2];
2789 }
2790
2791 uri = mongoc_uri_new_with_error (uri_string, &error);
2792 if (!uri) {
2793 fprintf (stderr,
2794 "failed to parse URI: %s\n"
2795 "error message: %s\n",
2796 uri_string,
2797 error.message);
2798 return EXIT_FAILURE;
2799 }
2800
2801 client = mongoc_client_new_from_uri (uri);
2802 if (!client) {
2803 return EXIT_FAILURE;
2804 }
2805
2806 mongoc_client_set_error_api (client, 2);
2807 db = mongoc_client_get_database (client, "test");
2808
2809 /* ascending index on field "x" */
2810 bson_init (&keys);
2811 BSON_APPEND_INT32 (&keys, "x", 1);
2812 index_name = mongoc_collection_keys_to_index_string (&keys);
2813 create_indexes = BCON_NEW ("createIndexes",
2814 BCON_UTF8 (collection_name),
2815 "indexes",
2816 "[",
2817 "{",
2818 "key",
2819 BCON_DOCUMENT (&keys),
2820 "name",
2821 BCON_UTF8 (index_name),
2822 "}",
2823 "]");
2824
2825 r = mongoc_database_write_command_with_opts (
2826 db, create_indexes, NULL /* opts */, &reply, &error);
2827
2828 reply_str = bson_as_json (&reply, NULL);
2829 printf ("%s\n", reply_str);
2830
2831 if (!r) {
2832 fprintf (stderr, "Error in createIndexes: %s\n", error.message);
2833 }
2834
2835 bson_free (index_name);
2836 bson_free (reply_str);
2837 bson_destroy (&reply);
2838 bson_destroy (create_indexes);
2839 mongoc_database_destroy (db);
2840 mongoc_uri_destroy (uri);
2841 mongoc_client_destroy (client);
2842
2843 mongoc_cleanup ();
2844
2845 return r ? EXIT_SUCCESS : EXIT_FAILURE;
2846 }
2847
2848
2850 GDB
2851 This repository contains a .gdbinit file that contains helper functions
2852 to aid debugging of data structures. GDB will load this file
2853 automatically if you have added the directory which contains the
2854 .gdbinit file to GDB's auto-load safe-path, and you start GDB from the
2855 directory which holds the .gdbinit file.
2856
2857 You can see the safe-path with show auto-load safe-path on a GDB
2858 prompt. You can configure it by setting it in ~/.gdbinit with:
2859
2860 add-auto-load-safe-path /path/to/mongo-c-driver
2861
2862 If you haven't added the path to your auto-load safe-path, or start GDB
2863 in another directory, load the file with:
2864
2865 source path/to/mongo-c-driver/.gdbinit
2866
2867 The .gdbinit file defines the printbson function, which shows the con‐
2868 tents of a bson_t * variable. If you have a local bson_t, then you
2869 must prefix the variable with a &.
2870
2871 An example GDB session looks like:
2872
2873 (gdb) printbson bson
2874 ALLOC [0x555556cd7310 + 0] (len=475)
2875 {
2876 'bool' : true,
2877 'int32' : NumberInt("42"),
2878 'int64' : NumberLong("3000000042"),
2879 'string' : "Stŕìñg",
2880 'objectId' : ObjectID("5A1442F3122D331C3C6757E1"),
2881 'utcDateTime' : UTCDateTime(1511277299031),
2882 'arrayOfInts' : [
2883 '0' : NumberInt("1"),
2884 '1' : NumberInt("2")
2885 ],
2886 'embeddedDocument' : {
2887 'arrayOfStrings' : [
2888 '0' : "one",
2889 '1' : "two"
2890 ],
2891 'double' : 2.718280,
2892 'notherDoc' : {
2893 'true' : NumberInt("1"),
2894 'false' : false
2895 }
2896 },
2897 'binary' : Binary("02", "3031343532333637"),
2898 'regex' : Regex("@[a-z]+@", "im"),
2899 'null' : null,
2900 'js' : JavaScript("print foo"),
2901 'jsws' : JavaScript("print foo") with scope: {
2902 'f' : NumberInt("42"),
2903 'a' : [
2904 '0' : 3.141593,
2905 '1' : 2.718282
2906 ]
2907 },
2908 'timestamp' : Timestamp(4294967295, 4294967295),
2909 'double' : 3.141593
2910 }
2911
2912 LLDB
2913 This repository also includes a script that customizes LLDB's standard
2914 print command to print a bson_t or bson_t * as JSON:
2915
2916 (lldb) print b
2917 (bson_t) $0 = {"x": 1, "y": 2}
2918
2919 The custom bson command provides more options:
2920
2921 (lldb) bson --verbose b
2922 len=19
2923 flags=INLINE|STATIC
2924 {
2925 "x": 1,
2926 "y": 2
2927 }
2928 (lldb) bson --raw b
2929 '\x13\x00\x00\x00\x10x\x00\x01\x00\x00\x00\x10y\x00\x02\x00\x00\x00\x00'
2930
2931 Type help bson for a list of options.
2932
2933 The script requires a build of libbson with debug symbols, and an in‐
2934 stallation of PyMongo. Install PyMongo with:
2935
2936 python -m pip install pymongo
2937
2938 If you see "No module named pip" then you must install pip, then run
2939 the previous command again.
2940
2941 Create a file ~/.lldbinit containing:
2942
2943 command script import /path/to/mongo-c-driver/lldb_bson.py
2944
2945 If you see "bson command installed by lldb_bson" at the beginning of
2946 your LLDB session, you've installed the script correctly.
2947
2948 Debug assertions
2949 To enable runtime debug assertions, configure with -DENABLE_DEBUG_AS‐
2950 SERTIONS=ON.
2951
2953 New in MongoDB 4.2, Client-Side Field Level Encryption (also referred
2954 to as Client-Side Encryption) allows administrators and developers to
2955 encrypt specific data fields in addition to other MongoDB encryption
2956 features.
2957
2958 With Client-Side Encryption, developers can encrypt fields client side
2959 without any server-side configuration or directives. Client-Side En‐
2960 cryption supports workloads where applications must guarantee that
2961 unauthorized parties, including server administrators, cannot read the
2962 encrypted data.
2963
2964 Automatic encryption, where sensitive fields in commands are encrypted
2965 automatically, requires an Enterprise-only process to do query analy‐
2966 sis.
2967
2968 Installation
2969 libmongocrypt
2970 There is a separate library, libmongocrypt, that must be installed
2971 prior to configuring libmongoc to enable Client-Side Encryption.
2972
2973 libmongocrypt depends on libbson. To build libmongoc with Client-Side
2974 Encryption support you must:
2975
2976 1. Install libbson
2977
2978 2. Build and install libmongocrypt
2979
2980 3. Build libmongoc
2981
2982 To install libbson, follow the instructions to install with a package
2983 manager: Install libbson with a Package Manager or build from source
2984 with cmake (disable building libmongoc with -DENABLE_MONGOC=OFF):
2985
2986 $ cd mongo-c-driver
2987 $ mkdir cmake-build && cd cmake-build
2988 $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGOC=OFF ..
2989 $ cmake --build . --target install
2990
2991 To build and install libmongocrypt, clone the repository and configure
2992 as follows:
2993
2994 $ cd libmongocrypt
2995 $ mkdir cmake-build && cd cmake-build
2996 $ cmake -DENABLE_SHARED_BSON=ON ..
2997 $ cmake --build . --target install
2998
2999 Then, you should be able to build libmongoc with Client-Side Encryp‐
3000 tion.
3001
3002 $ cd mongo-c-driver
3003 $ mkdir cmake-build && cd cmake-build
3004 $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGOC=ON -DENABLE_CLIENT_SIDE_ENCRYPTION=ON ..
3005 $ cmake --build . --target install
3006
3007 mongocryptd
3008 The mongocryptd binary is required for automatic Client-Side Encryption
3009 and is included as a component in the MongoDB Enterprise Server pack‐
3010 age. For detailed installation instructions see the MongoDB documenta‐
3011 tion on mongocryptd.
3012
3013 mongocryptd performs the following:
3014
3015 • Parses the automatic encryption rules specified to the database con‐
3016 nection. If the JSON schema contains invalid automatic encryption
3017 syntax or any document validation syntax, mongocryptd returns an er‐
3018 ror.
3019
3020 • Uses the specified automatic encryption rules to mark fields in read
3021 and write operations for encryption.
3022
3023 • Rejects read/write operations that may return unexpected or incorrect
3024 results when applied to an encrypted field. For supported and unsup‐
3025 ported operations, see Read/Write Support with Automatic Field Level
3026 Encryption.
3027
3028 A mongoc_client_t configured with auto encryption will automatically
3029 spawn the mongocryptd process from the application's PATH. Applications
3030 can control the spawning behavior as part of the automatic encryption
3031 options. For example, to set a custom path to the mongocryptd process,
3032 set the mongocryptdSpawnPath with mongoc_auto_encryption_opts_set_ex‐
3033 tra().
3034
3035 bson_t *extra = BCON_NEW ("mongocryptdSpawnPath", "/path/to/mongocryptd");
3036 mongoc_auto_encryption_opts_set_extra (opts, extra);
3037
3038 To control the logging output of mongocryptd pass mongocryptdSpawnArgs
3039 to mongoc_auto_encryption_opts_set_extra():
3040
3041 bson_t *extra = BCON_NEW ("mongocryptdSpawnArgs",
3042 "[", "--logpath=/path/to/mongocryptd.log", "--logappend", "]");
3043 mongoc_auto_encryption_opts_set_extra (opts, extra);
3044
3045 If your application wishes to manage the mongocryptd process manually,
3046 it is possible to disable spawning mongocryptd:
3047
3048 bson_t *extra = BCON_NEW ("mongocryptdBypassSpawn",
3049 BCON_BOOL(true), "mongocryptdURI", "mongodb://localhost:27020");
3050 mongoc_auto_encryption_opts_set_extra (opts, extra);
3051
3052 mongocryptd is only responsible for supporting automatic Client-Side
3053 Encryption in the driver and does not itself perform any encryption or
3054 decryption.
3055
3056 Automatic Client-Side Field Level Encryption
3057 Automatic Client-Side Encryption is enabled by calling mon‐
3058 goc_client_enable_auto_encryption() on a mongoc_client_t. The following
3059 examples show how to set up automatic client-side field level encryp‐
3060 tion using mongoc_client_encryption_t to create a new encryption data
3061 key.
3062
3063 NOTE:
3064 Automatic client-side field level encryption requires MongoDB 4.2
3065 enterprise or a MongoDB 4.2 Atlas cluster. The community version of
3066 the server supports automatic decryption as well as Explicit Encryp‐
3067 tion.
3068
3069 Providing Local Automatic Encryption Rules
3070 The following example shows how to specify automatic encryption rules
3071 using a schema map set with mongoc_auto_encryp‐
3072 tion_opts_set_schema_map(). The automatic encryption rules are ex‐
3073 pressed using a strict subset of the JSON Schema syntax.
3074
3075 Supplying a schema map provides more security than relying on JSON
3076 Schemas obtained from the server. It protects against a malicious
3077 server advertising a false JSON Schema, which could trick the client
3078 into sending unencrypted data that should be encrypted.
3079
3080 JSON Schemas supplied in the schema map only apply to configuring auto‐
3081 matic client-side field level encryption. Other validation rules in the
3082 JSON schema will not be enforced by the driver and will result in an
3083 error:
3084
3085 client-side-encryption-schema-map.c
3086
3087 #include <mongoc/mongoc.h>
3088 #include <stdio.h>
3089 #include <stdlib.h>
3090
3091 #include "client-side-encryption-helpers.h"
3092
3093 /* Helper method to create a new data key in the key vault, a schema to use that
3094 * key, and writes the schema to a file for later use. */
3095 static bool
3096 create_schema_file (bson_t *kms_providers,
3097 const char *keyvault_db,
3098 const char *keyvault_coll,
3099 mongoc_client_t *keyvault_client,
3100 bson_error_t *error)
3101 {
3102 mongoc_client_encryption_t *client_encryption = NULL;
3103 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3104 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3105 bson_value_t datakey_id = {0};
3106 char *keyaltnames[] = {"mongoc_encryption_example_1"};
3107 bson_t *schema = NULL;
3108 char *schema_string = NULL;
3109 size_t schema_string_len;
3110 FILE *outfile = NULL;
3111 bool ret = false;
3112
3113 client_encryption_opts = mongoc_client_encryption_opts_new ();
3114 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3115 kms_providers);
3116 mongoc_client_encryption_opts_set_keyvault_namespace (
3117 client_encryption_opts, keyvault_db, keyvault_coll);
3118 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3119 keyvault_client);
3120
3121 client_encryption =
3122 mongoc_client_encryption_new (client_encryption_opts, error);
3123 if (!client_encryption) {
3124 goto fail;
3125 }
3126
3127 /* Create a new data key and json schema for the encryptedField.
3128 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3129 */
3130 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3131 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3132 datakey_opts, keyaltnames, 1);
3133 if (!mongoc_client_encryption_create_datakey (
3134 client_encryption, "local", datakey_opts, &datakey_id, error)) {
3135 goto fail;
3136 }
3137
3138 /* Create a schema describing that "encryptedField" is a string encrypted
3139 * with the newly created data key using deterministic encryption. */
3140 schema = BCON_NEW ("properties",
3141 "{",
3142 "encryptedField",
3143 "{",
3144 "encrypt",
3145 "{",
3146 "keyId",
3147 "[",
3148 BCON_BIN (datakey_id.value.v_binary.subtype,
3149 datakey_id.value.v_binary.data,
3150 datakey_id.value.v_binary.data_len),
3151 "]",
3152 "bsonType",
3153 "string",
3154 "algorithm",
3155 MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3156 "}",
3157 "}",
3158 "}",
3159 "bsonType",
3160 "object");
3161
3162 /* Use canonical JSON so that other drivers and tools will be
3163 * able to parse the MongoDB extended JSON file. */
3164 schema_string = bson_as_canonical_extended_json (schema, &schema_string_len);
3165 outfile = fopen ("jsonSchema.json", "w");
3166 if (0 == fwrite (schema_string, sizeof (char), schema_string_len, outfile)) {
3167 fprintf (stderr, "failed to write to file\n");
3168 goto fail;
3169 }
3170
3171 ret = true;
3172 fail:
3173 mongoc_client_encryption_destroy (client_encryption);
3174 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3175 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3176 bson_free (schema_string);
3177 bson_destroy (schema);
3178 bson_value_destroy (&datakey_id);
3179 if (outfile) {
3180 fclose (outfile);
3181 }
3182 return true;
3183 }
3184
3185 /* This example demonstrates how to use automatic encryption with a client-side
3186 * schema map using the enterprise version of MongoDB */
3187 int
3188 main (int argc, char **argv)
3189 {
3190 /* The collection used to store the encryption data keys. */
3191 #define KEYVAULT_DB "encryption"
3192 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3193 /* The collection used to store the encrypted documents in this example. */
3194 #define ENCRYPTED_DB "test"
3195 #define ENCRYPTED_COLL "coll"
3196
3197 int exit_status = EXIT_FAILURE;
3198 bool ret;
3199 uint8_t *local_masterkey = NULL;
3200 uint32_t local_masterkey_len;
3201 bson_t *kms_providers = NULL;
3202 bson_error_t error = {0};
3203 bson_t *index_keys = NULL;
3204 char *index_name = NULL;
3205 bson_t *create_index_cmd = NULL;
3206 bson_json_reader_t *reader = NULL;
3207 bson_t schema = BSON_INITIALIZER;
3208 bson_t *schema_map = NULL;
3209
3210 /* The MongoClient used to access the key vault (keyvault_namespace). */
3211 mongoc_client_t *keyvault_client = NULL;
3212 mongoc_collection_t *keyvault_coll = NULL;
3213 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3214 mongoc_client_t *client = NULL;
3215 mongoc_collection_t *coll = NULL;
3216 bson_t *to_insert = NULL;
3217 mongoc_client_t *unencrypted_client = NULL;
3218 mongoc_collection_t *unencrypted_coll = NULL;
3219
3220 mongoc_init ();
3221
3222 /* Configure the master key. This must be the same master key that was used
3223 * to create the encryption key. */
3224 local_masterkey =
3225 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3226 if (!local_masterkey || local_masterkey_len != 96) {
3227 fprintf (stderr,
3228 "Specify LOCAL_MASTERKEY environment variable as a "
3229 "secure random 96 byte hex value.\n");
3230 goto fail;
3231 }
3232
3233 kms_providers = BCON_NEW ("local",
3234 "{",
3235 "key",
3236 BCON_BIN (0, local_masterkey, local_masterkey_len),
3237 "}");
3238
3239 /* Set up the key vault for this example. */
3240 keyvault_client = mongoc_client_new (
3241 "mongodb://localhost/?appname=client-side-encryption-keyvault");
3242 keyvault_coll = mongoc_client_get_collection (
3243 keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3244 mongoc_collection_drop (keyvault_coll, NULL);
3245
3246 /* Create a unique index to ensure that two data keys cannot share the same
3247 * keyAltName. This is recommended practice for the key vault. */
3248 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3249 index_name = mongoc_collection_keys_to_index_string (index_keys);
3250 create_index_cmd = BCON_NEW ("createIndexes",
3251 KEYVAULT_COLL,
3252 "indexes",
3253 "[",
3254 "{",
3255 "key",
3256 BCON_DOCUMENT (index_keys),
3257 "name",
3258 index_name,
3259 "unique",
3260 BCON_BOOL (true),
3261 "partialFilterExpression",
3262 "{",
3263 "keyAltNames",
3264 "{",
3265 "$exists",
3266 BCON_BOOL (true),
3267 "}",
3268 "}",
3269 "}",
3270 "]");
3271 ret = mongoc_client_command_simple (keyvault_client,
3272 KEYVAULT_DB,
3273 create_index_cmd,
3274 NULL /* read prefs */,
3275 NULL /* reply */,
3276 &error);
3277
3278 if (!ret) {
3279 goto fail;
3280 }
3281
3282 /* Create a new data key and a schema using it for encryption. Save the
3283 * schema to the file jsonSchema.json */
3284 ret = create_schema_file (
3285 kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3286
3287 if (!ret) {
3288 goto fail;
3289 }
3290
3291 /* Load the JSON Schema and construct the local schema_map option. */
3292 reader = bson_json_reader_new_from_file ("jsonSchema.json", &error);
3293 if (!reader) {
3294 goto fail;
3295 }
3296
3297 bson_json_reader_read (reader, &schema, &error);
3298
3299 /* Construct the schema map, mapping the namespace of the collection to the
3300 * schema describing encryption. */
3301 schema_map =
3302 BCON_NEW (ENCRYPTED_DB "." ENCRYPTED_COLL, BCON_DOCUMENT (&schema));
3303
3304 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3305 mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3306 keyvault_client);
3307 mongoc_auto_encryption_opts_set_keyvault_namespace (
3308 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3309 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3310 kms_providers);
3311 mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts,
3312 schema_map);
3313
3314 client =
3315 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3316
3317 /* Enable automatic encryption. It will determine that encryption is
3318 * necessary from the schema map instead of relying on the server to provide
3319 * a schema. */
3320 ret = mongoc_client_enable_auto_encryption (
3321 client, auto_encryption_opts, &error);
3322 if (!ret) {
3323 goto fail;
3324 }
3325
3326 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3327
3328 /* Clear old data */
3329 mongoc_collection_drop (coll, NULL);
3330
3331 to_insert = BCON_NEW ("encryptedField", "123456789");
3332 ret = mongoc_collection_insert_one (
3333 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3334 if (!ret) {
3335 goto fail;
3336 }
3337 printf ("decrypted document: ");
3338 if (!print_one_document (coll, &error)) {
3339 goto fail;
3340 }
3341 printf ("\n");
3342
3343 unencrypted_client = mongoc_client_new (
3344 "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3345 unencrypted_coll = mongoc_client_get_collection (
3346 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3347 printf ("encrypted document: ");
3348 if (!print_one_document (unencrypted_coll, &error)) {
3349 goto fail;
3350 }
3351 printf ("\n");
3352
3353 exit_status = EXIT_SUCCESS;
3354 fail:
3355 if (error.code) {
3356 fprintf (stderr, "error: %s\n", error.message);
3357 }
3358
3359 bson_free (local_masterkey);
3360 bson_destroy (kms_providers);
3361 mongoc_collection_destroy (keyvault_coll);
3362 bson_destroy (index_keys);
3363 bson_free (index_name);
3364 bson_destroy (create_index_cmd);
3365 bson_json_reader_destroy (reader);
3366 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3367 mongoc_collection_destroy (coll);
3368 mongoc_client_destroy (client);
3369 bson_destroy (to_insert);
3370 mongoc_collection_destroy (unencrypted_coll);
3371 mongoc_client_destroy (unencrypted_client);
3372 mongoc_client_destroy (keyvault_client);
3373 bson_destroy (&schema);
3374 bson_destroy (schema_map);
3375 mongoc_cleanup ();
3376 return exit_status;
3377 }
3378
3379 Server-Side Field Level Encryption Enforcement
3380 The MongoDB 4.2 server supports using schema validation to enforce en‐
3381 cryption of specific fields in a collection. This schema validation
3382 will prevent an application from inserting unencrypted values for any
3383 fields marked with the "encrypt" JSON schema keyword.
3384
3385 The following example shows how to set up automatic client-side field
3386 level encryption using mongoc_client_encryption_t to create a new en‐
3387 cryption data key and create a collection with the Automatic Encryption
3388 JSON Schema Syntax:
3389
3390 client-side-encryption-server-schema.c
3391
3392 #include <mongoc/mongoc.h>
3393 #include <stdio.h>
3394 #include <stdlib.h>
3395
3396 #include "client-side-encryption-helpers.h"
3397
3398 /* Helper method to create and return a JSON schema to use for encryption.
3399 The caller will use the returned schema for server-side encryption validation.
3400 */
3401 static bson_t *
3402 create_schema (bson_t *kms_providers,
3403 const char *keyvault_db,
3404 const char *keyvault_coll,
3405 mongoc_client_t *keyvault_client,
3406 bson_error_t *error)
3407 {
3408 mongoc_client_encryption_t *client_encryption = NULL;
3409 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3410 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3411 bson_value_t datakey_id = {0};
3412 char *keyaltnames[] = {"mongoc_encryption_example_2"};
3413 bson_t *schema = NULL;
3414
3415 client_encryption_opts = mongoc_client_encryption_opts_new ();
3416 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3417 kms_providers);
3418 mongoc_client_encryption_opts_set_keyvault_namespace (
3419 client_encryption_opts, keyvault_db, keyvault_coll);
3420 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3421 keyvault_client);
3422
3423 client_encryption =
3424 mongoc_client_encryption_new (client_encryption_opts, error);
3425 if (!client_encryption) {
3426 goto fail;
3427 }
3428
3429 /* Create a new data key and json schema for the encryptedField.
3430 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3431 */
3432 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3433 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3434 datakey_opts, keyaltnames, 1);
3435 if (!mongoc_client_encryption_create_datakey (
3436 client_encryption, "local", datakey_opts, &datakey_id, error)) {
3437 goto fail;
3438 }
3439
3440 /* Create a schema describing that "encryptedField" is a string encrypted
3441 * with the newly created data key using deterministic encryption. */
3442 schema = BCON_NEW ("properties",
3443 "{",
3444 "encryptedField",
3445 "{",
3446 "encrypt",
3447 "{",
3448 "keyId",
3449 "[",
3450 BCON_BIN (datakey_id.value.v_binary.subtype,
3451 datakey_id.value.v_binary.data,
3452 datakey_id.value.v_binary.data_len),
3453 "]",
3454 "bsonType",
3455 "string",
3456 "algorithm",
3457 MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3458 "}",
3459 "}",
3460 "}",
3461 "bsonType",
3462 "object");
3463
3464 fail:
3465 mongoc_client_encryption_destroy (client_encryption);
3466 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3467 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3468 bson_value_destroy (&datakey_id);
3469 return schema;
3470 }
3471
3472 /* This example demonstrates how to use automatic encryption with a server-side
3473 * schema using the enterprise version of MongoDB */
3474 int
3475 main (int argc, char **argv)
3476 {
3477 /* The collection used to store the encryption data keys. */
3478 #define KEYVAULT_DB "encryption"
3479 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3480 /* The collection used to store the encrypted documents in this example. */
3481 #define ENCRYPTED_DB "test"
3482 #define ENCRYPTED_COLL "coll"
3483
3484 int exit_status = EXIT_FAILURE;
3485 bool ret;
3486 uint8_t *local_masterkey = NULL;
3487 uint32_t local_masterkey_len;
3488 bson_t *kms_providers = NULL;
3489 bson_error_t error = {0};
3490 bson_t *index_keys = NULL;
3491 char *index_name = NULL;
3492 bson_t *create_index_cmd = NULL;
3493 bson_json_reader_t *reader = NULL;
3494 bson_t *schema = NULL;
3495
3496 /* The MongoClient used to access the key vault (keyvault_namespace). */
3497 mongoc_client_t *keyvault_client = NULL;
3498 mongoc_collection_t *keyvault_coll = NULL;
3499 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3500 mongoc_client_t *client = NULL;
3501 mongoc_collection_t *coll = NULL;
3502 bson_t *to_insert = NULL;
3503 mongoc_client_t *unencrypted_client = NULL;
3504 mongoc_collection_t *unencrypted_coll = NULL;
3505 bson_t *create_cmd = NULL;
3506 bson_t *create_cmd_opts = NULL;
3507 mongoc_write_concern_t *wc = NULL;
3508
3509 mongoc_init ();
3510
3511 /* Configure the master key. This must be the same master key that was used
3512 * to create
3513 * the encryption key. */
3514 local_masterkey =
3515 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3516 if (!local_masterkey || local_masterkey_len != 96) {
3517 fprintf (stderr,
3518 "Specify LOCAL_MASTERKEY environment variable as a "
3519 "secure random 96 byte hex value.\n");
3520 goto fail;
3521 }
3522
3523 kms_providers = BCON_NEW ("local",
3524 "{",
3525 "key",
3526 BCON_BIN (0, local_masterkey, local_masterkey_len),
3527 "}");
3528
3529 /* Set up the key vault for this example. */
3530 keyvault_client = mongoc_client_new (
3531 "mongodb://localhost/?appname=client-side-encryption-keyvault");
3532 keyvault_coll = mongoc_client_get_collection (
3533 keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3534 mongoc_collection_drop (keyvault_coll, NULL);
3535
3536 /* Create a unique index to ensure that two data keys cannot share the same
3537 * keyAltName. This is recommended practice for the key vault. */
3538 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3539 index_name = mongoc_collection_keys_to_index_string (index_keys);
3540 create_index_cmd = BCON_NEW ("createIndexes",
3541 KEYVAULT_COLL,
3542 "indexes",
3543 "[",
3544 "{",
3545 "key",
3546 BCON_DOCUMENT (index_keys),
3547 "name",
3548 index_name,
3549 "unique",
3550 BCON_BOOL (true),
3551 "partialFilterExpression",
3552 "{",
3553 "keyAltNames",
3554 "{",
3555 "$exists",
3556 BCON_BOOL (true),
3557 "}",
3558 "}",
3559 "}",
3560 "]");
3561 ret = mongoc_client_command_simple (keyvault_client,
3562 KEYVAULT_DB,
3563 create_index_cmd,
3564 NULL /* read prefs */,
3565 NULL /* reply */,
3566 &error);
3567
3568 if (!ret) {
3569 goto fail;
3570 }
3571
3572 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3573 mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3574 keyvault_client);
3575 mongoc_auto_encryption_opts_set_keyvault_namespace (
3576 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3577 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3578 kms_providers);
3579 schema = create_schema (
3580 kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3581
3582 if (!schema) {
3583 goto fail;
3584 }
3585
3586 client =
3587 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3588 ret = mongoc_client_enable_auto_encryption (
3589 client, auto_encryption_opts, &error);
3590 if (!ret) {
3591 goto fail;
3592 }
3593
3594 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3595
3596 /* Clear old data */
3597 mongoc_collection_drop (coll, NULL);
3598
3599 /* Create the collection with the encryption JSON Schema. */
3600 create_cmd = BCON_NEW ("create",
3601 ENCRYPTED_COLL,
3602 "validator",
3603 "{",
3604 "$jsonSchema",
3605 BCON_DOCUMENT (schema),
3606 "}");
3607 wc = mongoc_write_concern_new ();
3608 mongoc_write_concern_set_wmajority (wc, 0);
3609 create_cmd_opts = bson_new ();
3610 mongoc_write_concern_append (wc, create_cmd_opts);
3611 ret = mongoc_client_command_with_opts (client,
3612 ENCRYPTED_DB,
3613 create_cmd,
3614 NULL /* read prefs */,
3615 create_cmd_opts,
3616 NULL /* reply */,
3617 &error);
3618 if (!ret) {
3619 goto fail;
3620 }
3621
3622 to_insert = BCON_NEW ("encryptedField", "123456789");
3623 ret = mongoc_collection_insert_one (
3624 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3625 if (!ret) {
3626 goto fail;
3627 }
3628 printf ("decrypted document: ");
3629 if (!print_one_document (coll, &error)) {
3630 goto fail;
3631 }
3632 printf ("\n");
3633
3634 unencrypted_client = mongoc_client_new (
3635 "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3636 unencrypted_coll = mongoc_client_get_collection (
3637 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3638 printf ("encrypted document: ");
3639 if (!print_one_document (unencrypted_coll, &error)) {
3640 goto fail;
3641 }
3642 printf ("\n");
3643
3644 /* Expect a server-side error if inserting with the unencrypted collection.
3645 */
3646 ret = mongoc_collection_insert_one (
3647 unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3648 if (!ret) {
3649 printf ("insert with unencrypted collection failed: %s\n", error.message);
3650 memset (&error, 0, sizeof (error));
3651 }
3652
3653 exit_status = EXIT_SUCCESS;
3654 fail:
3655 if (error.code) {
3656 fprintf (stderr, "error: %s\n", error.message);
3657 }
3658
3659 bson_free (local_masterkey);
3660 bson_destroy (kms_providers);
3661 mongoc_collection_destroy (keyvault_coll);
3662 bson_destroy (index_keys);
3663 bson_free (index_name);
3664 bson_destroy (create_index_cmd);
3665 bson_json_reader_destroy (reader);
3666 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3667 mongoc_collection_destroy (coll);
3668 mongoc_client_destroy (client);
3669 bson_destroy (to_insert);
3670 mongoc_collection_destroy (unencrypted_coll);
3671 mongoc_client_destroy (unencrypted_client);
3672 mongoc_client_destroy (keyvault_client);
3673 bson_destroy (schema);
3674 bson_destroy (create_cmd);
3675 bson_destroy (create_cmd_opts);
3676 mongoc_write_concern_destroy (wc);
3677
3678 mongoc_cleanup ();
3679 return exit_status;
3680 }
3681
3682 Explicit Encryption
3683 Explicit encryption is a MongoDB community feature and does not use the
3684 mongocryptd process. Explicit encryption is provided by the mon‐
3685 goc_client_encryption_t class, for example:
3686
3687 client-side-encryption-explicit.c
3688
3689 #include <mongoc/mongoc.h>
3690 #include <stdio.h>
3691 #include <stdlib.h>
3692
3693 #include "client-side-encryption-helpers.h"
3694
3695 /* This example demonstrates how to use explicit encryption and decryption using
3696 * the community version of MongoDB */
3697 int
3698 main (int argc, char **argv)
3699 {
3700 /* The collection used to store the encryption data keys. */
3701 #define KEYVAULT_DB "encryption"
3702 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3703 /* The collection used to store the encrypted documents in this example. */
3704 #define ENCRYPTED_DB "test"
3705 #define ENCRYPTED_COLL "coll"
3706
3707 int exit_status = EXIT_FAILURE;
3708 bool ret;
3709 uint8_t *local_masterkey = NULL;
3710 uint32_t local_masterkey_len;
3711 bson_t *kms_providers = NULL;
3712 bson_error_t error = {0};
3713 bson_t *index_keys = NULL;
3714 char *index_name = NULL;
3715 bson_t *create_index_cmd = NULL;
3716 bson_t *schema = NULL;
3717 mongoc_client_t *client = NULL;
3718 mongoc_collection_t *coll = NULL;
3719 mongoc_collection_t *keyvault_coll = NULL;
3720 bson_t *to_insert = NULL;
3721 bson_t *create_cmd = NULL;
3722 bson_t *create_cmd_opts = NULL;
3723 mongoc_write_concern_t *wc = NULL;
3724 mongoc_client_encryption_t *client_encryption = NULL;
3725 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3726 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3727 char *keyaltnames[] = {"mongoc_encryption_example_3"};
3728 bson_value_t datakey_id = {0};
3729 bson_value_t encrypted_field = {0};
3730 bson_value_t to_encrypt = {0};
3731 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3732 bson_value_t decrypted = {0};
3733
3734 mongoc_init ();
3735
3736 /* Configure the master key. This must be the same master key that was used
3737 * to create the encryption key. */
3738 local_masterkey =
3739 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3740 if (!local_masterkey || local_masterkey_len != 96) {
3741 fprintf (stderr,
3742 "Specify LOCAL_MASTERKEY environment variable as a "
3743 "secure random 96 byte hex value.\n");
3744 goto fail;
3745 }
3746
3747 kms_providers = BCON_NEW ("local",
3748 "{",
3749 "key",
3750 BCON_BIN (0, local_masterkey, local_masterkey_len),
3751 "}");
3752
3753 /* The mongoc_client_t used to read/write application data. */
3754 client =
3755 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3756 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3757
3758 /* Clear old data */
3759 mongoc_collection_drop (coll, NULL);
3760
3761 /* Set up the key vault for this example. */
3762 keyvault_coll =
3763 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3764 mongoc_collection_drop (keyvault_coll, NULL);
3765
3766 /* Create a unique index to ensure that two data keys cannot share the same
3767 * keyAltName. This is recommended practice for the key vault. */
3768 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3769 index_name = mongoc_collection_keys_to_index_string (index_keys);
3770 create_index_cmd = BCON_NEW ("createIndexes",
3771 KEYVAULT_COLL,
3772 "indexes",
3773 "[",
3774 "{",
3775 "key",
3776 BCON_DOCUMENT (index_keys),
3777 "name",
3778 index_name,
3779 "unique",
3780 BCON_BOOL (true),
3781 "partialFilterExpression",
3782 "{",
3783 "keyAltNames",
3784 "{",
3785 "$exists",
3786 BCON_BOOL (true),
3787 "}",
3788 "}",
3789 "}",
3790 "]");
3791 ret = mongoc_client_command_simple (client,
3792 KEYVAULT_DB,
3793 create_index_cmd,
3794 NULL /* read prefs */,
3795 NULL /* reply */,
3796 &error);
3797
3798 if (!ret) {
3799 goto fail;
3800 }
3801
3802 client_encryption_opts = mongoc_client_encryption_opts_new ();
3803 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3804 kms_providers);
3805 mongoc_client_encryption_opts_set_keyvault_namespace (
3806 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3807
3808 /* Set a mongoc_client_t to use for reading/writing to the key vault. This
3809 * can be the same mongoc_client_t used by the main application. */
3810 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3811 client);
3812 client_encryption =
3813 mongoc_client_encryption_new (client_encryption_opts, &error);
3814 if (!client_encryption) {
3815 goto fail;
3816 }
3817
3818 /* Create a new data key for the encryptedField.
3819 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3820 */
3821 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3822 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3823 datakey_opts, keyaltnames, 1);
3824 if (!mongoc_client_encryption_create_datakey (
3825 client_encryption, "local", datakey_opts, &datakey_id, &error)) {
3826 goto fail;
3827 }
3828
3829 /* Explicitly encrypt a field */
3830 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
3831 mongoc_client_encryption_encrypt_opts_set_algorithm (
3832 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
3833 mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id);
3834 to_encrypt.value_type = BSON_TYPE_UTF8;
3835 to_encrypt.value.v_utf8.str = "123456789";
3836 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
3837
3838 ret = mongoc_client_encryption_encrypt (
3839 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
3840 if (!ret) {
3841 goto fail;
3842 }
3843
3844 to_insert = bson_new ();
3845 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
3846 ret = mongoc_collection_insert_one (
3847 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3848 if (!ret) {
3849 goto fail;
3850 }
3851
3852 printf ("encrypted document: ");
3853 if (!print_one_document (coll, &error)) {
3854 goto fail;
3855 }
3856 printf ("\n");
3857
3858 /* Explicitly decrypt a field */
3859 ret = mongoc_client_encryption_decrypt (
3860 client_encryption, &encrypted_field, &decrypted, &error);
3861 if (!ret) {
3862 goto fail;
3863 }
3864 printf ("decrypted value: %s\n", decrypted.value.v_utf8.str);
3865
3866 exit_status = EXIT_SUCCESS;
3867 fail:
3868 if (error.code) {
3869 fprintf (stderr, "error: %s\n", error.message);
3870 }
3871
3872 bson_free (local_masterkey);
3873 bson_destroy (kms_providers);
3874 mongoc_collection_destroy (keyvault_coll);
3875 bson_destroy (index_keys);
3876 bson_free (index_name);
3877 bson_destroy (create_index_cmd);
3878 mongoc_collection_destroy (coll);
3879 mongoc_client_destroy (client);
3880 bson_destroy (to_insert);
3881 bson_destroy (schema);
3882 bson_destroy (create_cmd);
3883 bson_destroy (create_cmd_opts);
3884 mongoc_write_concern_destroy (wc);
3885 mongoc_client_encryption_destroy (client_encryption);
3886 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3887 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3888 bson_value_destroy (&encrypted_field);
3889 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
3890 bson_value_destroy (&decrypted);
3891 bson_value_destroy (&datakey_id);
3892
3893 mongoc_cleanup ();
3894 return exit_status;
3895 }
3896
3897 Explicit Encryption with Automatic Decryption
3898 Although automatic encryption requires MongoDB 4.2 enterprise or a Mon‐
3899 goDB 4.2 Atlas cluster, automatic decryption is supported for all
3900 users. To configure automatic decryption without automatic encryption
3901 set bypass_auto_encryption=True in mongoc_auto_encryption_opts_t:
3902
3903 client-side-encryption-auto-decryption.c
3904
3905 #include <mongoc/mongoc.h>
3906 #include <stdio.h>
3907 #include <stdlib.h>
3908
3909 #include "client-side-encryption-helpers.h"
3910
3911 /* This example demonstrates how to set up automatic decryption without
3912 * automatic encryption using the community version of MongoDB */
3913 int
3914 main (int argc, char **argv)
3915 {
3916 /* The collection used to store the encryption data keys. */
3917 #define KEYVAULT_DB "encryption"
3918 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3919 /* The collection used to store the encrypted documents in this example. */
3920 #define ENCRYPTED_DB "test"
3921 #define ENCRYPTED_COLL "coll"
3922
3923 int exit_status = EXIT_FAILURE;
3924 bool ret;
3925 uint8_t *local_masterkey = NULL;
3926 uint32_t local_masterkey_len;
3927 bson_t *kms_providers = NULL;
3928 bson_error_t error = {0};
3929 bson_t *index_keys = NULL;
3930 char *index_name = NULL;
3931 bson_t *create_index_cmd = NULL;
3932 bson_t *schema = NULL;
3933 mongoc_client_t *client = NULL;
3934 mongoc_collection_t *coll = NULL;
3935 mongoc_collection_t *keyvault_coll = NULL;
3936 bson_t *to_insert = NULL;
3937 bson_t *create_cmd = NULL;
3938 bson_t *create_cmd_opts = NULL;
3939 mongoc_write_concern_t *wc = NULL;
3940 mongoc_client_encryption_t *client_encryption = NULL;
3941 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3942 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3943 char *keyaltnames[] = {"mongoc_encryption_example_4"};
3944 bson_value_t datakey_id = {0};
3945 bson_value_t encrypted_field = {0};
3946 bson_value_t to_encrypt = {0};
3947 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3948 bson_value_t decrypted = {0};
3949 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3950 mongoc_client_t *unencrypted_client = NULL;
3951 mongoc_collection_t *unencrypted_coll = NULL;
3952
3953 mongoc_init ();
3954
3955 /* Configure the master key. This must be the same master key that was used
3956 * to create the encryption key. */
3957 local_masterkey =
3958 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3959 if (!local_masterkey || local_masterkey_len != 96) {
3960 fprintf (stderr,
3961 "Specify LOCAL_MASTERKEY environment variable as a "
3962 "secure random 96 byte hex value.\n");
3963 goto fail;
3964 }
3965
3966 kms_providers = BCON_NEW ("local",
3967 "{",
3968 "key",
3969 BCON_BIN (0, local_masterkey, local_masterkey_len),
3970 "}");
3971
3972 client =
3973 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3974 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3975 mongoc_auto_encryption_opts_set_keyvault_namespace (
3976 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3977 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3978 kms_providers);
3979
3980 /* Setting bypass_auto_encryption to true disables automatic encryption but
3981 * keeps the automatic decryption behavior. bypass_auto_encryption will also
3982 * disable spawning mongocryptd */
3983 mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts,
3984 true);
3985
3986 /* Once bypass_auto_encryption is set, community users can enable auto
3987 * encryption on the client. This will, in fact, only perform automatic
3988 * decryption. */
3989 ret = mongoc_client_enable_auto_encryption (
3990 client, auto_encryption_opts, &error);
3991 if (!ret) {
3992 goto fail;
3993 }
3994
3995 /* Now that automatic decryption is on, we can test it by inserting a
3996 * document with an explicitly encrypted value into the collection. When we
3997 * look up the document later, it should be automatically decrypted for us.
3998 */
3999 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
4000
4001 /* Clear old data */
4002 mongoc_collection_drop (coll, NULL);
4003
4004 /* Set up the key vault for this example. */
4005 keyvault_coll =
4006 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
4007 mongoc_collection_drop (keyvault_coll, NULL);
4008
4009 /* Create a unique index to ensure that two data keys cannot share the same
4010 * keyAltName. This is recommended practice for the key vault. */
4011 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
4012 index_name = mongoc_collection_keys_to_index_string (index_keys);
4013 create_index_cmd = BCON_NEW ("createIndexes",
4014 KEYVAULT_COLL,
4015 "indexes",
4016 "[",
4017 "{",
4018 "key",
4019 BCON_DOCUMENT (index_keys),
4020 "name",
4021 index_name,
4022 "unique",
4023 BCON_BOOL (true),
4024 "partialFilterExpression",
4025 "{",
4026 "keyAltNames",
4027 "{",
4028 "$exists",
4029 BCON_BOOL (true),
4030 "}",
4031 "}",
4032 "}",
4033 "]");
4034 ret = mongoc_client_command_simple (client,
4035 KEYVAULT_DB,
4036 create_index_cmd,
4037 NULL /* read prefs */,
4038 NULL /* reply */,
4039 &error);
4040
4041 if (!ret) {
4042 goto fail;
4043 }
4044
4045 client_encryption_opts = mongoc_client_encryption_opts_new ();
4046 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
4047 kms_providers);
4048 mongoc_client_encryption_opts_set_keyvault_namespace (
4049 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
4050
4051 /* The key vault client is used for reading to/from the key vault. This can
4052 * be the same mongoc_client_t used by the application. */
4053 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
4054 client);
4055 client_encryption =
4056 mongoc_client_encryption_new (client_encryption_opts, &error);
4057 if (!client_encryption) {
4058 goto fail;
4059 }
4060
4061 /* Create a new data key for the encryptedField.
4062 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
4063 */
4064 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
4065 mongoc_client_encryption_datakey_opts_set_keyaltnames (
4066 datakey_opts, keyaltnames, 1);
4067 ret = mongoc_client_encryption_create_datakey (
4068 client_encryption, "local", datakey_opts, &datakey_id, &error);
4069 if (!ret) {
4070 goto fail;
4071 }
4072
4073 /* Explicitly encrypt a field. */
4074 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
4075 mongoc_client_encryption_encrypt_opts_set_algorithm (
4076 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
4077 mongoc_client_encryption_encrypt_opts_set_keyaltname (
4078 encrypt_opts, "mongoc_encryption_example_4");
4079 to_encrypt.value_type = BSON_TYPE_UTF8;
4080 to_encrypt.value.v_utf8.str = "123456789";
4081 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
4082
4083 ret = mongoc_client_encryption_encrypt (
4084 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
4085 if (!ret) {
4086 goto fail;
4087 }
4088
4089 to_insert = bson_new ();
4090 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
4091 ret = mongoc_collection_insert_one (
4092 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
4093 if (!ret) {
4094 goto fail;
4095 }
4096
4097 /* When we retrieve the document, any encrypted fields will get automatically
4098 * decrypted by the driver. */
4099 printf ("decrypted document: ");
4100 if (!print_one_document (coll, &error)) {
4101 goto fail;
4102 }
4103 printf ("\n");
4104
4105 unencrypted_client =
4106 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
4107 unencrypted_coll = mongoc_client_get_collection (
4108 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
4109
4110 printf ("encrypted document: ");
4111 if (!print_one_document (unencrypted_coll, &error)) {
4112 goto fail;
4113 }
4114 printf ("\n");
4115
4116 exit_status = EXIT_SUCCESS;
4117 fail:
4118 if (error.code) {
4119 fprintf (stderr, "error: %s\n", error.message);
4120 }
4121
4122 bson_free (local_masterkey);
4123 bson_destroy (kms_providers);
4124 mongoc_collection_destroy (keyvault_coll);
4125 bson_destroy (index_keys);
4126 bson_free (index_name);
4127 bson_destroy (create_index_cmd);
4128 mongoc_collection_destroy (coll);
4129 mongoc_client_destroy (client);
4130 bson_destroy (to_insert);
4131 bson_destroy (schema);
4132 bson_destroy (create_cmd);
4133 bson_destroy (create_cmd_opts);
4134 mongoc_write_concern_destroy (wc);
4135 mongoc_client_encryption_destroy (client_encryption);
4136 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
4137 mongoc_client_encryption_opts_destroy (client_encryption_opts);
4138 bson_value_destroy (&encrypted_field);
4139 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
4140 bson_value_destroy (&decrypted);
4141 bson_value_destroy (&datakey_id);
4142 mongoc_collection_destroy (unencrypted_coll);
4143 mongoc_client_destroy (unencrypted_client);
4144 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
4145
4146 mongoc_cleanup ();
4147 return exit_status;
4148 }
4149
4151 MongoDB, Inc
4152
4154 2017-present, MongoDB, Inc
4155
4156
4157
4158
41591.20.0 Nov 18, 2021 MONGOC_GUIDES(3)