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
590 Tutorial. To establish a connection with authentication options en‐
591 abled, 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
830 launches monitoring threads in the background. Monitoring threads inde‐
831 pendently connect to all servers in the connection string. As monitor‐
832 ing threads receive hello responses from the servers, they update the
833 shared view of the server topology. Additional monitoring threads and
834 connections are created as new servers are discovered. Monitoring
835 threads are terminated when servers are removed from the shared view of
836 the server 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
848 mongoc_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
864 pool. (See mongoc_uri_t.) If waitQueueTimeoutMS is specified, then it
865 is 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
1112 mongoc_collection_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
1125 mongoc_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 (void)
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 (void)
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 (void)
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 (void)
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 (void)
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 (collection, NULL);
1793 doc = BCON_NEW ("_id", BCON_UTF8 ("one"));
1794 mongoc_bulk_operation_insert (bulk, doc);
1795 bson_destroy (doc);
1796
1797 doc = BCON_NEW ("_id", BCON_UTF8 ("One"));
1798 mongoc_bulk_operation_insert (bulk, doc);
1799 bson_destroy (doc);
1800
1801 /* "One" normally sorts before "one"; make "one" come first */
1802 opts = BCON_NEW ("collation",
1803 "{",
1804 "locale",
1805 BCON_UTF8 ("en_US"),
1806 "caseFirst",
1807 BCON_UTF8 ("lower"),
1808 "}");
1809
1810 /* set x=1 on the document with _id "One", which now sorts after "one" */
1811 update = BCON_NEW ("$set", "{", "x", BCON_INT64 (1), "}");
1812 selector = BCON_NEW ("_id", "{", "$gt", BCON_UTF8 ("one"), "}");
1813 mongoc_bulk_operation_update_one_with_opts (
1814 bulk, selector, update, opts, &error);
1815
1816 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1817
1818 str = bson_as_canonical_extended_json (&reply, NULL);
1819 printf ("%s\n", str);
1820 bson_free (str);
1821
1822 if (!ret) {
1823 printf ("Error: %s\n", error.message);
1824 }
1825
1826 bson_destroy (&reply);
1827 bson_destroy (update);
1828 bson_destroy (selector);
1829 bson_destroy (opts);
1830 mongoc_bulk_operation_destroy (bulk);
1831 }
1832
1833 int
1834 main (void)
1835 {
1836 mongoc_client_t *client;
1837 mongoc_collection_t *collection;
1838 const char *uri_string = "mongodb://localhost/?appname=bulk-collation";
1839 mongoc_uri_t *uri;
1840 bson_error_t error;
1841
1842 mongoc_init ();
1843
1844 uri = mongoc_uri_new_with_error (uri_string, &error);
1845 if (!uri) {
1846 fprintf (stderr,
1847 "failed to parse URI: %s\n"
1848 "error message: %s\n",
1849 uri_string,
1850 error.message);
1851 return EXIT_FAILURE;
1852 }
1853
1854 client = mongoc_client_new_from_uri (uri);
1855 if (!client) {
1856 return EXIT_FAILURE;
1857 }
1858
1859 mongoc_client_set_error_api (client, 2);
1860 collection = mongoc_client_get_collection (client, "db", "collection");
1861 bulk_collation (collection);
1862
1863 mongoc_uri_destroy (uri);
1864 mongoc_collection_destroy (collection);
1865 mongoc_client_destroy (client);
1866
1867 mongoc_cleanup ();
1868
1869 return EXIT_SUCCESS;
1870 }
1871
1872
1873 Running the above example will result in:
1874
1875 { "nInserted" : 2,
1876 "nMatched" : 1,
1877 "nModified" : 1,
1878 "nRemoved" : 0,
1879 "nUpserted" : 0,
1880 "writeErrors" : [ ]
1881 }
1882
1883 Unacknowledged Bulk Writes
1884 Set "w" to zero for an unacknowledged write. The driver sends unac‐
1885 knowledged writes using the legacy opcodes OP_INSERT, OP_UPDATE, and
1886 OP_DELETE.
1887
1888 bulk6.c
1889
1890 #include <mongoc/mongoc.h>
1891 #include <stdio.h>
1892
1893 static void
1894 bulk6 (mongoc_collection_t *collection)
1895 {
1896 bson_t opts = BSON_INITIALIZER;
1897 mongoc_write_concern_t *wc;
1898 mongoc_bulk_operation_t *bulk;
1899 bson_error_t error;
1900 bson_t *doc;
1901 bson_t *selector;
1902 bson_t reply;
1903 char *str;
1904 bool ret;
1905
1906 wc = mongoc_write_concern_new ();
1907 mongoc_write_concern_set_w (wc, 0);
1908 mongoc_write_concern_append (wc, &opts);
1909
1910 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1911
1912 doc = BCON_NEW ("_id", BCON_INT32 (10));
1913 mongoc_bulk_operation_insert (bulk, doc);
1914 bson_destroy (doc);
1915
1916 selector = BCON_NEW ("_id", BCON_INT32 (11));
1917 mongoc_bulk_operation_remove_one (bulk, selector);
1918 bson_destroy (selector);
1919
1920 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1921
1922 str = bson_as_canonical_extended_json (&reply, NULL);
1923 printf ("%s\n", str);
1924 bson_free (str);
1925
1926 if (!ret) {
1927 printf ("Error: %s\n", error.message);
1928 }
1929
1930 bson_destroy (&reply);
1931 mongoc_bulk_operation_destroy (bulk);
1932 mongoc_write_concern_destroy (wc);
1933 bson_destroy (&opts);
1934 }
1935
1936 int
1937 main (void)
1938 {
1939 mongoc_client_t *client;
1940 mongoc_collection_t *collection;
1941 const char *uri_string = "mongodb://localhost/?appname=bulk6-example";
1942 mongoc_uri_t *uri;
1943 bson_error_t error;
1944
1945 mongoc_init ();
1946
1947 uri = mongoc_uri_new_with_error (uri_string, &error);
1948 if (!uri) {
1949 fprintf (stderr,
1950 "failed to parse URI: %s\n"
1951 "error message: %s\n",
1952 uri_string,
1953 error.message);
1954 return EXIT_FAILURE;
1955 }
1956
1957 client = mongoc_client_new_from_uri (uri);
1958 if (!client) {
1959 return EXIT_FAILURE;
1960 }
1961
1962 mongoc_client_set_error_api (client, 2);
1963 collection = mongoc_client_get_collection (client, "test", "test");
1964
1965 bulk6 (collection);
1966
1967 mongoc_uri_destroy (uri);
1968 mongoc_collection_destroy (collection);
1969 mongoc_client_destroy (client);
1970
1971 mongoc_cleanup ();
1972
1973 return EXIT_SUCCESS;
1974 }
1975
1976
1977 The reply document is empty:
1978
1979 { }
1980
1981 Further Reading
1982 See the Driver Bulk API Spec, which describes bulk write operations for
1983 all MongoDB drivers.
1984
1986 This document provides a number of practical examples that display the
1987 capabilities of the aggregation framework.
1988
1989 The Aggregations using the Zip Codes Data Set examples uses a publicly
1990 available data set of all zipcodes and populations in the United
1991 States. These data are available at: zips.json.
1992
1993 Requirements
1994 Let's check if everything is installed.
1995
1996 Use the following command to load zips.json data set into mongod in‐
1997 stance:
1998
1999 $ mongoimport --drop -d test -c zipcodes zips.json
2000
2001 Let's use the MongoDB shell to verify that everything was imported suc‐
2002 cessfully.
2003
2004 $ mongo test
2005 connecting to: test
2006 > db.zipcodes.count()
2007 29467
2008 > db.zipcodes.findOne()
2009 {
2010 "_id" : "35004",
2011 "city" : "ACMAR",
2012 "loc" : [
2013 -86.51557,
2014 33.584132
2015 ],
2016 "pop" : 6055,
2017 "state" : "AL"
2018 }
2019
2020 Aggregations using the Zip Codes Data Set
2021 Each document in this collection has the following form:
2022
2023 {
2024 "_id" : "35004",
2025 "city" : "Acmar",
2026 "state" : "AL",
2027 "pop" : 6055,
2028 "loc" : [-86.51557, 33.584132]
2029 }
2030
2031 In these documents:
2032
2033 • The _id field holds the zipcode as a string.
2034
2035 • The city field holds the city name.
2036
2037 • The state field holds the two letter state abbreviation.
2038
2039 • The pop field holds the population.
2040
2041 • The loc field holds the location as a [latitude, longitude] array.
2042
2043 States with Populations Over 10 Million
2044 To get all states with a population greater than 10 million, use the
2045 following aggregation pipeline:
2046
2047 aggregation1.c
2048
2049 #include <mongoc/mongoc.h>
2050 #include <stdio.h>
2051
2052 static void
2053 print_pipeline (mongoc_collection_t *collection)
2054 {
2055 mongoc_cursor_t *cursor;
2056 bson_error_t error;
2057 const bson_t *doc;
2058 bson_t *pipeline;
2059 char *str;
2060
2061 pipeline = BCON_NEW ("pipeline",
2062 "[",
2063 "{",
2064 "$group",
2065 "{",
2066 "_id",
2067 "$state",
2068 "total_pop",
2069 "{",
2070 "$sum",
2071 "$pop",
2072 "}",
2073 "}",
2074 "}",
2075 "{",
2076 "$match",
2077 "{",
2078 "total_pop",
2079 "{",
2080 "$gte",
2081 BCON_INT32 (10000000),
2082 "}",
2083 "}",
2084 "}",
2085 "]");
2086
2087 cursor = mongoc_collection_aggregate (
2088 collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL);
2089
2090 while (mongoc_cursor_next (cursor, &doc)) {
2091 str = bson_as_canonical_extended_json (doc, NULL);
2092 printf ("%s\n", str);
2093 bson_free (str);
2094 }
2095
2096 if (mongoc_cursor_error (cursor, &error)) {
2097 fprintf (stderr, "Cursor Failure: %s\n", error.message);
2098 }
2099
2100 mongoc_cursor_destroy (cursor);
2101 bson_destroy (pipeline);
2102 }
2103
2104 int
2105 main (void)
2106 {
2107 mongoc_client_t *client;
2108 mongoc_collection_t *collection;
2109 const char *uri_string =
2110 "mongodb://localhost:27017/?appname=aggregation-example";
2111 mongoc_uri_t *uri;
2112 bson_error_t error;
2113
2114 mongoc_init ();
2115
2116 uri = mongoc_uri_new_with_error (uri_string, &error);
2117 if (!uri) {
2118 fprintf (stderr,
2119 "failed to parse URI: %s\n"
2120 "error message: %s\n",
2121 uri_string,
2122 error.message);
2123 return EXIT_FAILURE;
2124 }
2125
2126 client = mongoc_client_new_from_uri (uri);
2127 if (!client) {
2128 return EXIT_FAILURE;
2129 }
2130
2131 mongoc_client_set_error_api (client, 2);
2132 collection = mongoc_client_get_collection (client, "test", "zipcodes");
2133
2134 print_pipeline (collection);
2135
2136 mongoc_uri_destroy (uri);
2137 mongoc_collection_destroy (collection);
2138 mongoc_client_destroy (client);
2139
2140 mongoc_cleanup ();
2141
2142 return EXIT_SUCCESS;
2143 }
2144
2145
2146 You should see a result like the following:
2147
2148 { "_id" : "PA", "total_pop" : 11881643 }
2149 { "_id" : "OH", "total_pop" : 10847115 }
2150 { "_id" : "NY", "total_pop" : 17990455 }
2151 { "_id" : "FL", "total_pop" : 12937284 }
2152 { "_id" : "TX", "total_pop" : 16986510 }
2153 { "_id" : "IL", "total_pop" : 11430472 }
2154 { "_id" : "CA", "total_pop" : 29760021 }
2155
2156 The above aggregation pipeline is build from two pipeline operators:
2157 $group and $match.
2158
2159 The $group pipeline operator requires _id field where we specify group‐
2160 ing; remaining fields specify how to generate composite value and must
2161 use one of the group aggregation functions: $addToSet, $first, $last,
2162 $max, $min, $avg, $push, $sum. The $match pipeline operator syntax is
2163 the same as the read operation query syntax.
2164
2165 The $group process reads all documents and for each state it creates a
2166 separate document, for example:
2167
2168 { "_id" : "WA", "total_pop" : 4866692 }
2169
2170 The total_pop field uses the $sum aggregation function to sum the val‐
2171 ues of all pop fields in the source documents.
2172
2173 Documents created by $group are piped to the $match pipeline operator.
2174 It returns the documents with the value of total_pop field greater than
2175 or equal to 10 million.
2176
2177 Average City Population by State
2178 To get the first three states with the greatest average population per
2179 city, use the following aggregation:
2180
2181 pipeline = BCON_NEW ("pipeline", "[",
2182 "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}",
2183 "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}",
2184 "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}",
2185 "{", "$limit", BCON_INT32 (3) "}",
2186 "]");
2187
2188 This aggregate pipeline produces:
2189
2190 { "_id" : "DC", "avg_city_pop" : 303450.0 }
2191 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2192 { "_id" : "CA", "avg_city_pop" : 27735.341099720412 }
2193
2194 The above aggregation pipeline is build from three pipeline operators:
2195 $group, $sort and $limit.
2196
2197 The first $group operator creates the following documents:
2198
2199 { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 }
2200
2201 Note, that the $group operator can't use nested documents except the
2202 _id field.
2203
2204 The second $group uses these documents to create the following docu‐
2205 ments:
2206
2207 { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2208
2209 These documents are sorted by the avg_city_pop field in descending or‐
2210 der. Finally, the $limit pipeline operator returns the first 3 docu‐
2211 ments from the sorted set.
2212
2214 This document provides some practical, simple, examples to demonstrate
2215 the distinct and mapReduce commands.
2216
2217 Setup
2218 First we'll write some code to insert sample data:
2219
2220 doc-common-insert.c
2221
2222 /* Don't try to compile this file on its own. It's meant to be #included
2223 by example code */
2224
2225 /* Insert some sample data */
2226 bool
2227 insert_data (mongoc_collection_t *collection)
2228 {
2229 mongoc_bulk_operation_t *bulk;
2230 enum N { ndocs = 4 };
2231 bson_t *docs[ndocs];
2232 bson_error_t error;
2233 int i = 0;
2234 bool ret;
2235
2236 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
2237
2238 docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
2239 docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
2240 docs[2] = BCON_NEW (
2241 "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
2242 docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
2243
2244 for (i = 0; i < ndocs; i++) {
2245 mongoc_bulk_operation_insert (bulk, docs[i]);
2246 bson_destroy (docs[i]);
2247 docs[i] = NULL;
2248 }
2249
2250 ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
2251
2252 if (!ret) {
2253 fprintf (stderr, "Error inserting data: %s\n", error.message);
2254 }
2255
2256 mongoc_bulk_operation_destroy (bulk);
2257 return ret;
2258 }
2259
2260 /* A helper which we'll use a lot later on */
2261 void
2262 print_res (const bson_t *reply)
2263 {
2264 char *str;
2265 BSON_ASSERT (reply);
2266 str = bson_as_canonical_extended_json (reply, NULL);
2267 printf ("%s\n", str);
2268 bson_free (str);
2269 }
2270
2271
2272 "distinct" command
2273 This is how to use the distinct command to get the distinct values of x
2274 which are greater than 1:
2275
2276 distinct.c
2277
2278 bool
2279 distinct (mongoc_database_t *database)
2280 {
2281 bson_t *command;
2282 bson_t reply;
2283 bson_error_t error;
2284 bool res;
2285 bson_iter_t iter;
2286 bson_iter_t array_iter;
2287 double val;
2288
2289 command = BCON_NEW ("distinct",
2290 BCON_UTF8 (COLLECTION_NAME),
2291 "key",
2292 BCON_UTF8 ("x"),
2293 "query",
2294 "{",
2295 "x",
2296 "{",
2297 "$gt",
2298 BCON_DOUBLE (1.0),
2299 "}",
2300 "}");
2301 res =
2302 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2303 if (!res) {
2304 fprintf (stderr, "Error with distinct: %s\n", error.message);
2305 goto cleanup;
2306 }
2307
2308 /* Do something with reply (in this case iterate through the values) */
2309 if (!(bson_iter_init_find (&iter, &reply, "values") &&
2310 BSON_ITER_HOLDS_ARRAY (&iter) &&
2311 bson_iter_recurse (&iter, &array_iter))) {
2312 fprintf (stderr, "Couldn't extract \"values\" field from response\n");
2313 goto cleanup;
2314 }
2315
2316 while (bson_iter_next (&array_iter)) {
2317 if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) {
2318 val = bson_iter_double (&array_iter);
2319 printf ("Next double: %f\n", val);
2320 }
2321 }
2322
2323 cleanup:
2324 /* cleanup */
2325 bson_destroy (command);
2326 bson_destroy (&reply);
2327 return res;
2328 }
2329
2330
2331 "mapReduce" - basic example
2332 A simple example using the map reduce framework. It simply adds up the
2333 number of occurrences of each "tag".
2334
2335 First define the map and reduce functions:
2336
2337 constants.c
2338
2339 const char *const COLLECTION_NAME = "things";
2340
2341 /* Our map function just emits a single (key, 1) pair for each tag
2342 in the array: */
2343 const char *const MAPPER = "function () {"
2344 "this.tags.forEach(function(z) {"
2345 "emit(z, 1);"
2346 "});"
2347 "}";
2348
2349 /* The reduce function sums over all of the emitted values for a
2350 given key: */
2351 const char *const REDUCER = "function (key, values) {"
2352 "var total = 0;"
2353 "for (var i = 0; i < values.length; i++) {"
2354 "total += values[i];"
2355 "}"
2356 "return total;"
2357 "}";
2358 /* Note We can't just return values.length as the reduce function
2359 might be called iteratively on the results of other reduce
2360 steps. */
2361
2362
2363 Run the mapReduce command. Use the generic command helpers (e.g.
2364 mongoc_database_command_simple()). Do not the read command helpers
2365 (e.g. mongoc_database_read_command_with_opts()) because they are con‐
2366 sidered retryable read operations. If retryable reads are enabled,
2367 those operations will retry once on a retryable error, giving undesir‐
2368 able behavior for mapReduce.
2369
2370 map-reduce-basic.c
2371
2372 bool
2373 map_reduce_basic (mongoc_database_t *database)
2374 {
2375 bson_t reply;
2376 bson_t *command;
2377 bool res;
2378 bson_error_t error;
2379 mongoc_cursor_t *cursor;
2380 const bson_t *doc;
2381
2382 bool query_done = false;
2383
2384 const char *out_collection_name = "outCollection";
2385 mongoc_collection_t *out_collection;
2386
2387 /* Empty find query */
2388 bson_t find_query = BSON_INITIALIZER;
2389
2390 /* Construct the mapReduce command */
2391
2392 /* Other arguments can also be specified here, like "query" or
2393 "limit" and so on */
2394 command = BCON_NEW ("mapReduce",
2395 BCON_UTF8 (COLLECTION_NAME),
2396 "map",
2397 BCON_CODE (MAPPER),
2398 "reduce",
2399 BCON_CODE (REDUCER),
2400 "out",
2401 BCON_UTF8 (out_collection_name));
2402 res =
2403 mongoc_database_command_simple (database, command, NULL, &reply, &error);
2404
2405 if (!res) {
2406 fprintf (stderr, "MapReduce failed: %s\n", error.message);
2407 goto cleanup;
2408 }
2409
2410 /* Do something with the reply (it doesn't contain the mapReduce results) */
2411 print_res (&reply);
2412
2413 /* Now we'll query outCollection to see what the results are */
2414 out_collection =
2415 mongoc_database_get_collection (database, out_collection_name);
2416 cursor = mongoc_collection_find_with_opts (
2417 out_collection, &find_query, NULL, NULL);
2418 query_done = true;
2419
2420 /* Do something with the results */
2421 while (mongoc_cursor_next (cursor, &doc)) {
2422 print_res (doc);
2423 }
2424
2425 if (mongoc_cursor_error (cursor, &error)) {
2426 fprintf (stderr, "ERROR: %s\n", error.message);
2427 res = false;
2428 goto cleanup;
2429 }
2430
2431 cleanup:
2432 /* cleanup */
2433 if (query_done) {
2434 mongoc_cursor_destroy (cursor);
2435 mongoc_collection_destroy (out_collection);
2436 }
2437
2438 bson_destroy (&reply);
2439 bson_destroy (command);
2440
2441 return res;
2442 }
2443
2444
2445 "mapReduce" - more complicated example
2446 You must have replica set running for this.
2447
2448 In this example we contact a secondary in the replica set and do an
2449 "inline" map reduce, so the results are returned immediately:
2450
2451 map-reduce-advanced.c
2452
2453 bool
2454 map_reduce_advanced (mongoc_database_t *database)
2455 {
2456 bson_t *command;
2457 bson_error_t error;
2458 bool res = true;
2459 mongoc_cursor_t *cursor;
2460 mongoc_read_prefs_t *read_pref;
2461 const bson_t *doc;
2462
2463 /* Construct the mapReduce command */
2464 /* Other arguments can also be specified here, like "query" or "limit"
2465 and so on */
2466
2467 /* Read the results inline from a secondary replica */
2468 command = BCON_NEW ("mapReduce",
2469 BCON_UTF8 (COLLECTION_NAME),
2470 "map",
2471 BCON_CODE (MAPPER),
2472 "reduce",
2473 BCON_CODE (REDUCER),
2474 "out",
2475 "{",
2476 "inline",
2477 "1",
2478 "}");
2479
2480 read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
2481 cursor = mongoc_database_command (
2482 database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref);
2483
2484 /* Do something with the results */
2485 while (mongoc_cursor_next (cursor, &doc)) {
2486 print_res (doc);
2487 }
2488
2489 if (mongoc_cursor_error (cursor, &error)) {
2490 fprintf (stderr, "ERROR: %s\n", error.message);
2491 res = false;
2492 }
2493
2494 mongoc_cursor_destroy (cursor);
2495 mongoc_read_prefs_destroy (read_pref);
2496 bson_destroy (command);
2497
2498 return res;
2499 }
2500
2501
2502 Running the Examples
2503 Here's how to run the example code
2504
2505 basic-aggregation.c
2506
2507 /*
2508 * Copyright 2016 MongoDB, Inc.
2509 *
2510 * Licensed under the Apache License, Version 2.0 (the "License");
2511 * you may not use this file except in compliance with the License.
2512 * You may obtain a copy of the License at
2513 *
2514 * http://www.apache.org/licenses/LICENSE-2.0
2515 *
2516 * Unless required by applicable law or agreed to in writing, software
2517 * distributed under the License is distributed on an "AS IS" BASIS,
2518 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2519 * See the License for the specific language governing permissions and
2520 * limitations under the License.
2521 */
2522
2523
2524 #include <mongoc/mongoc.h>
2525 #include <stdio.h>
2526
2527
2528 #include "constants.c"
2529
2530 #include "../doc-common-insert.c"
2531 #include "distinct.c"
2532 #include "map-reduce-basic.c"
2533 #include "map-reduce-advanced.c"
2534
2535
2536 int
2537 main (int argc, char *argv[])
2538 {
2539 mongoc_database_t *database = NULL;
2540 mongoc_client_t *client = NULL;
2541 mongoc_collection_t *collection = NULL;
2542 mongoc_uri_t *uri = NULL;
2543 bson_error_t error;
2544 char *host_and_port = NULL;
2545 int exit_code = EXIT_FAILURE;
2546
2547 if (argc != 2) {
2548 fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]);
2549 fprintf (stderr,
2550 "the connection string can be of the following forms:\n");
2551 fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
2552 fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
2553 fprintf (stderr,
2554 "mongodb://user:pass@localhost:27017\t"
2555 "local machine on port 27017, and authenticate with username "
2556 "user and password pass\n");
2557 return exit_code;
2558 }
2559
2560 mongoc_init ();
2561
2562 if (strncmp (argv[1], "mongodb://", 10) == 0) {
2563 host_and_port = bson_strdup (argv[1]);
2564 } else {
2565 host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
2566 }
2567
2568 uri = mongoc_uri_new_with_error (host_and_port, &error);
2569 if (!uri) {
2570 fprintf (stderr,
2571 "failed to parse URI: %s\n"
2572 "error message: %s\n",
2573 host_and_port,
2574 error.message);
2575 goto cleanup;
2576 }
2577
2578 client = mongoc_client_new_from_uri (uri);
2579 if (!client) {
2580 goto cleanup;
2581 }
2582
2583 mongoc_client_set_error_api (client, 2);
2584 database = mongoc_client_get_database (client, "test");
2585 collection = mongoc_database_get_collection (database, COLLECTION_NAME);
2586
2587 printf ("Inserting data\n");
2588 if (!insert_data (collection)) {
2589 goto cleanup;
2590 }
2591
2592 printf ("distinct\n");
2593 if (!distinct (database)) {
2594 goto cleanup;
2595 }
2596
2597 printf ("map reduce\n");
2598 if (!map_reduce_basic (database)) {
2599 goto cleanup;
2600 }
2601
2602 printf ("more complicated map reduce\n");
2603 if (!map_reduce_advanced (database)) {
2604 goto cleanup;
2605 }
2606
2607 exit_code = EXIT_SUCCESS;
2608
2609 cleanup:
2610 if (collection) {
2611 mongoc_collection_destroy (collection);
2612 }
2613
2614 if (database) {
2615 mongoc_database_destroy (database);
2616 }
2617
2618 if (client) {
2619 mongoc_client_destroy (client);
2620 }
2621
2622 if (uri) {
2623 mongoc_uri_destroy (uri);
2624 }
2625
2626 if (host_and_port) {
2627 bson_free (host_and_port);
2628 }
2629
2630 mongoc_cleanup ();
2631 return exit_code;
2632 }
2633
2634
2635 If you want to try the advanced map reduce example with a secondary,
2636 start a replica set (instructions for how to do this can be found
2637 here).
2638
2639 Otherwise, just start an instance of MongoDB:
2640
2641 $ mongod
2642
2643 Now compile and run the example program:
2644
2645 $ cd examples/basic_aggregation/
2646 $ gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0)
2647 $ ./agg-example localhost
2648
2649 Inserting data
2650 distinct
2651 Next double: 2.000000
2652 Next double: 3.000000
2653 map reduce
2654 { "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
2655 { "_id" : "cat", "value" : 63 }
2656 { "_id" : "dog", "value" : 42 }
2657 { "_id" : "mouse", "value" : 21 }
2658 more complicated map reduce
2659 { "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 }
2660
2662 Download and install libmongoc on your system, then open Visual Studio,
2663 select "File→New→Project...", and create a new Win32 Console Applica‐
2664 tion. [image]
2665
2666 Remember to switch the platform from 32-bit to 64-bit: [image]
2667
2668 Right-click on your console application in the Solution Explorer and
2669 select "Properties". Choose to edit properties for "All Configura‐
2670 tions", expand the "C/C++" options and choose "General". Add to the
2671 "Additional Include Directories" these paths:
2672
2673 C:\mongo-c-driver\include\libbson-1.0
2674 C:\mongo-c-driver\include\libmongoc-1.0
2675 [image]
2676
2677 (If you chose a different CMAKE_INSTALL_PREFIX when you ran CMake, your
2678 include paths will be different.)
2679
2680 Also in the Properties dialog, expand the "Linker" options and choose
2681 "Input", and add to the "Additional Dependencies" these libraries:
2682
2683 C:\mongo-c-driver\lib\bson-1.0.lib
2684 C:\mongo-c-driver\lib\mongoc-1.0.lib
2685 [image]
2686
2687 Adding these libraries as dependencies provides linker symbols to build
2688 your application, but to actually run it, libbson's and libmongoc's
2689 DLLs must be in your executable path. Select "Debugging" in the Proper‐
2690 ties dialog, and set the "Environment" option to:
2691
2692 PATH=c:/mongo-c-driver/bin
2693 [image]
2694
2695 Finally, include "mongoc/mongoc.h" in your project's "stdafx.h":
2696
2697 #include <mongoc/mongoc.h>
2698
2699 Static linking
2700 Following the instructions above, you have dynamically linked your ap‐
2701 plication to the libbson and libmongoc DLLs. This is usually the right
2702 choice. If you want to link statically instead, update your "Additional
2703 Dependencies" list by removing bson-1.0.lib and mongoc-1.0.lib and re‐
2704 placing them with these libraries:
2705
2706 C:\mongo-c-driver\lib\bson-static-1.0.lib
2707 C:\mongo-c-driver\lib\mongoc-static-1.0.lib
2708 ws2_32.lib
2709 Secur32.lib
2710 Crypt32.lib
2711 BCrypt.lib
2712 [image]
2713
2714 (To explain the purpose of each library: bson-static-1.0.lib and mon‐
2715 goc-static-1.0.lib are static archives of the driver code. The socket
2716 library ws2_32 is required by libbson, which uses the socket routine
2717 gethostname to help guarantee ObjectId uniqueness. The BCrypt library
2718 is used by libmongoc for TLS connections to MongoDB, and Secur32 and
2719 Crypt32 are required for enterprise authentication methods like Ker‐
2720 beros.)
2721
2722 Finally, define two preprocessor symbols before including mongoc/mon‐
2723 goc.h in your stdafx.h:
2724
2725 #define BSON_STATIC
2726 #define MONGOC_STATIC
2727 #include <mongoc/mongoc.h>
2728
2729 Making these changes to your project is only required for static link‐
2730 ing; for most people, the dynamic-linking instructions above are pre‐
2731 ferred.
2732
2733 Next Steps
2734 Now you can build and debug applications in Visual Studio that use
2735 libbson and libmongoc. Proceed to Making a Connection in the tutorial
2736 to learn how connect to MongoDB and perform operations.
2737
2739 To create indexes on a MongoDB collection, execute the createIndexes
2740 command with a command function like
2741 mongoc_database_write_command_with_opts() or
2742 mongoc_collection_write_command_with_opts(). See the MongoDB Manual en‐
2743 try 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
3033 mongoc_auto_encryption_opts_set_extra().
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
3058 mongoc_client_enable_auto_encryption() on a mongoc_client_t. The fol‐
3059 lowing examples show how to set up automatic client-side field level
3060 encryption using mongoc_client_encryption_t to create a new encryption
3061 data 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
3072 mongoc_auto_encryption_opts_set_schema_map(). The automatic encryption
3073 rules are expressed 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 ret;
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 (void)
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
3380 Server-Side Field Level Encryption Enforcement
3381 The MongoDB 4.2 server supports using schema validation to enforce en‐
3382 cryption of specific fields in a collection. This schema validation
3383 will prevent an application from inserting unencrypted values for any
3384 fields marked with the "encrypt" JSON schema keyword.
3385
3386 The following example shows how to set up automatic client-side field
3387 level encryption using mongoc_client_encryption_t to create a new en‐
3388 cryption data key and create a collection with the Automatic Encryption
3389 JSON Schema Syntax:
3390
3391 client-side-encryption-server-schema.c
3392
3393 #include <mongoc/mongoc.h>
3394 #include <stdio.h>
3395 #include <stdlib.h>
3396
3397 #include "client-side-encryption-helpers.h"
3398
3399 /* Helper method to create and return a JSON schema to use for encryption.
3400 The caller will use the returned schema for server-side encryption validation.
3401 */
3402 static bson_t *
3403 create_schema (bson_t *kms_providers,
3404 const char *keyvault_db,
3405 const char *keyvault_coll,
3406 mongoc_client_t *keyvault_client,
3407 bson_error_t *error)
3408 {
3409 mongoc_client_encryption_t *client_encryption = NULL;
3410 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3411 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3412 bson_value_t datakey_id = {0};
3413 char *keyaltnames[] = {"mongoc_encryption_example_2"};
3414 bson_t *schema = NULL;
3415
3416 client_encryption_opts = mongoc_client_encryption_opts_new ();
3417 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3418 kms_providers);
3419 mongoc_client_encryption_opts_set_keyvault_namespace (
3420 client_encryption_opts, keyvault_db, keyvault_coll);
3421 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3422 keyvault_client);
3423
3424 client_encryption =
3425 mongoc_client_encryption_new (client_encryption_opts, error);
3426 if (!client_encryption) {
3427 goto fail;
3428 }
3429
3430 /* Create a new data key and json schema for the encryptedField.
3431 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3432 */
3433 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3434 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3435 datakey_opts, keyaltnames, 1);
3436 if (!mongoc_client_encryption_create_datakey (
3437 client_encryption, "local", datakey_opts, &datakey_id, error)) {
3438 goto fail;
3439 }
3440
3441 /* Create a schema describing that "encryptedField" is a string encrypted
3442 * with the newly created data key using deterministic encryption. */
3443 schema = BCON_NEW ("properties",
3444 "{",
3445 "encryptedField",
3446 "{",
3447 "encrypt",
3448 "{",
3449 "keyId",
3450 "[",
3451 BCON_BIN (datakey_id.value.v_binary.subtype,
3452 datakey_id.value.v_binary.data,
3453 datakey_id.value.v_binary.data_len),
3454 "]",
3455 "bsonType",
3456 "string",
3457 "algorithm",
3458 MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3459 "}",
3460 "}",
3461 "}",
3462 "bsonType",
3463 "object");
3464
3465 fail:
3466 mongoc_client_encryption_destroy (client_encryption);
3467 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3468 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3469 bson_value_destroy (&datakey_id);
3470 return schema;
3471 }
3472
3473 /* This example demonstrates how to use automatic encryption with a server-side
3474 * schema using the enterprise version of MongoDB */
3475 int
3476 main (void)
3477 {
3478 /* The collection used to store the encryption data keys. */
3479 #define KEYVAULT_DB "encryption"
3480 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3481 /* The collection used to store the encrypted documents in this example. */
3482 #define ENCRYPTED_DB "test"
3483 #define ENCRYPTED_COLL "coll"
3484
3485 int exit_status = EXIT_FAILURE;
3486 bool ret;
3487 uint8_t *local_masterkey = NULL;
3488 uint32_t local_masterkey_len;
3489 bson_t *kms_providers = NULL;
3490 bson_error_t error = {0};
3491 bson_t *index_keys = NULL;
3492 char *index_name = NULL;
3493 bson_t *create_index_cmd = NULL;
3494 bson_json_reader_t *reader = NULL;
3495 bson_t *schema = NULL;
3496
3497 /* The MongoClient used to access the key vault (keyvault_namespace). */
3498 mongoc_client_t *keyvault_client = NULL;
3499 mongoc_collection_t *keyvault_coll = NULL;
3500 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3501 mongoc_client_t *client = NULL;
3502 mongoc_collection_t *coll = NULL;
3503 bson_t *to_insert = NULL;
3504 mongoc_client_t *unencrypted_client = NULL;
3505 mongoc_collection_t *unencrypted_coll = NULL;
3506 bson_t *create_cmd = NULL;
3507 bson_t *create_cmd_opts = NULL;
3508 mongoc_write_concern_t *wc = NULL;
3509
3510 mongoc_init ();
3511
3512 /* Configure the master key. This must be the same master key that was used
3513 * to create
3514 * the encryption key. */
3515 local_masterkey =
3516 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3517 if (!local_masterkey || local_masterkey_len != 96) {
3518 fprintf (stderr,
3519 "Specify LOCAL_MASTERKEY environment variable as a "
3520 "secure random 96 byte hex value.\n");
3521 goto fail;
3522 }
3523
3524 kms_providers = BCON_NEW ("local",
3525 "{",
3526 "key",
3527 BCON_BIN (0, local_masterkey, local_masterkey_len),
3528 "}");
3529
3530 /* Set up the key vault for this example. */
3531 keyvault_client = mongoc_client_new (
3532 "mongodb://localhost/?appname=client-side-encryption-keyvault");
3533 keyvault_coll = mongoc_client_get_collection (
3534 keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3535 mongoc_collection_drop (keyvault_coll, NULL);
3536
3537 /* Create a unique index to ensure that two data keys cannot share the same
3538 * keyAltName. This is recommended practice for the key vault. */
3539 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3540 index_name = mongoc_collection_keys_to_index_string (index_keys);
3541 create_index_cmd = BCON_NEW ("createIndexes",
3542 KEYVAULT_COLL,
3543 "indexes",
3544 "[",
3545 "{",
3546 "key",
3547 BCON_DOCUMENT (index_keys),
3548 "name",
3549 index_name,
3550 "unique",
3551 BCON_BOOL (true),
3552 "partialFilterExpression",
3553 "{",
3554 "keyAltNames",
3555 "{",
3556 "$exists",
3557 BCON_BOOL (true),
3558 "}",
3559 "}",
3560 "}",
3561 "]");
3562 ret = mongoc_client_command_simple (keyvault_client,
3563 KEYVAULT_DB,
3564 create_index_cmd,
3565 NULL /* read prefs */,
3566 NULL /* reply */,
3567 &error);
3568
3569 if (!ret) {
3570 goto fail;
3571 }
3572
3573 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3574 mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3575 keyvault_client);
3576 mongoc_auto_encryption_opts_set_keyvault_namespace (
3577 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3578 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3579 kms_providers);
3580 schema = create_schema (
3581 kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3582
3583 if (!schema) {
3584 goto fail;
3585 }
3586
3587 client =
3588 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3589 ret = mongoc_client_enable_auto_encryption (
3590 client, auto_encryption_opts, &error);
3591 if (!ret) {
3592 goto fail;
3593 }
3594
3595 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3596
3597 /* Clear old data */
3598 mongoc_collection_drop (coll, NULL);
3599
3600 /* Create the collection with the encryption JSON Schema. */
3601 create_cmd = BCON_NEW ("create",
3602 ENCRYPTED_COLL,
3603 "validator",
3604 "{",
3605 "$jsonSchema",
3606 BCON_DOCUMENT (schema),
3607 "}");
3608 wc = mongoc_write_concern_new ();
3609 mongoc_write_concern_set_wmajority (wc, 0);
3610 create_cmd_opts = bson_new ();
3611 mongoc_write_concern_append (wc, create_cmd_opts);
3612 ret = mongoc_client_command_with_opts (client,
3613 ENCRYPTED_DB,
3614 create_cmd,
3615 NULL /* read prefs */,
3616 create_cmd_opts,
3617 NULL /* reply */,
3618 &error);
3619 if (!ret) {
3620 goto fail;
3621 }
3622
3623 to_insert = BCON_NEW ("encryptedField", "123456789");
3624 ret = mongoc_collection_insert_one (
3625 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3626 if (!ret) {
3627 goto fail;
3628 }
3629 printf ("decrypted document: ");
3630 if (!print_one_document (coll, &error)) {
3631 goto fail;
3632 }
3633 printf ("\n");
3634
3635 unencrypted_client = mongoc_client_new (
3636 "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3637 unencrypted_coll = mongoc_client_get_collection (
3638 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3639 printf ("encrypted document: ");
3640 if (!print_one_document (unencrypted_coll, &error)) {
3641 goto fail;
3642 }
3643 printf ("\n");
3644
3645 /* Expect a server-side error if inserting with the unencrypted collection.
3646 */
3647 ret = mongoc_collection_insert_one (
3648 unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3649 if (!ret) {
3650 printf ("insert with unencrypted collection failed: %s\n", error.message);
3651 memset (&error, 0, sizeof (error));
3652 }
3653
3654 exit_status = EXIT_SUCCESS;
3655 fail:
3656 if (error.code) {
3657 fprintf (stderr, "error: %s\n", error.message);
3658 }
3659
3660 bson_free (local_masterkey);
3661 bson_destroy (kms_providers);
3662 mongoc_collection_destroy (keyvault_coll);
3663 bson_destroy (index_keys);
3664 bson_free (index_name);
3665 bson_destroy (create_index_cmd);
3666 bson_json_reader_destroy (reader);
3667 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3668 mongoc_collection_destroy (coll);
3669 mongoc_client_destroy (client);
3670 bson_destroy (to_insert);
3671 mongoc_collection_destroy (unencrypted_coll);
3672 mongoc_client_destroy (unencrypted_client);
3673 mongoc_client_destroy (keyvault_client);
3674 bson_destroy (schema);
3675 bson_destroy (create_cmd);
3676 bson_destroy (create_cmd_opts);
3677 mongoc_write_concern_destroy (wc);
3678
3679 mongoc_cleanup ();
3680 return exit_status;
3681 }
3682
3683
3684 Explicit Encryption
3685 Explicit encryption is a MongoDB community feature and does not use the
3686 mongocryptd process. Explicit encryption is provided by the
3687 mongoc_client_encryption_t class, for example:
3688
3689 client-side-encryption-explicit.c
3690
3691 #include <mongoc/mongoc.h>
3692 #include <stdio.h>
3693 #include <stdlib.h>
3694
3695 #include "client-side-encryption-helpers.h"
3696
3697 /* This example demonstrates how to use explicit encryption and decryption using
3698 * the community version of MongoDB */
3699 int
3700 main (void)
3701 {
3702 /* The collection used to store the encryption data keys. */
3703 #define KEYVAULT_DB "encryption"
3704 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3705 /* The collection used to store the encrypted documents in this example. */
3706 #define ENCRYPTED_DB "test"
3707 #define ENCRYPTED_COLL "coll"
3708
3709 int exit_status = EXIT_FAILURE;
3710 bool ret;
3711 uint8_t *local_masterkey = NULL;
3712 uint32_t local_masterkey_len;
3713 bson_t *kms_providers = NULL;
3714 bson_error_t error = {0};
3715 bson_t *index_keys = NULL;
3716 char *index_name = NULL;
3717 bson_t *create_index_cmd = NULL;
3718 bson_t *schema = NULL;
3719 mongoc_client_t *client = NULL;
3720 mongoc_collection_t *coll = NULL;
3721 mongoc_collection_t *keyvault_coll = NULL;
3722 bson_t *to_insert = NULL;
3723 bson_t *create_cmd = NULL;
3724 bson_t *create_cmd_opts = NULL;
3725 mongoc_write_concern_t *wc = NULL;
3726 mongoc_client_encryption_t *client_encryption = NULL;
3727 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3728 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3729 char *keyaltnames[] = {"mongoc_encryption_example_3"};
3730 bson_value_t datakey_id = {0};
3731 bson_value_t encrypted_field = {0};
3732 bson_value_t to_encrypt = {0};
3733 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3734 bson_value_t decrypted = {0};
3735
3736 mongoc_init ();
3737
3738 /* Configure the master key. This must be the same master key that was used
3739 * to create the encryption key. */
3740 local_masterkey =
3741 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3742 if (!local_masterkey || local_masterkey_len != 96) {
3743 fprintf (stderr,
3744 "Specify LOCAL_MASTERKEY environment variable as a "
3745 "secure random 96 byte hex value.\n");
3746 goto fail;
3747 }
3748
3749 kms_providers = BCON_NEW ("local",
3750 "{",
3751 "key",
3752 BCON_BIN (0, local_masterkey, local_masterkey_len),
3753 "}");
3754
3755 /* The mongoc_client_t used to read/write application data. */
3756 client =
3757 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3758 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3759
3760 /* Clear old data */
3761 mongoc_collection_drop (coll, NULL);
3762
3763 /* Set up the key vault for this example. */
3764 keyvault_coll =
3765 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3766 mongoc_collection_drop (keyvault_coll, NULL);
3767
3768 /* Create a unique index to ensure that two data keys cannot share the same
3769 * keyAltName. This is recommended practice for the key vault. */
3770 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3771 index_name = mongoc_collection_keys_to_index_string (index_keys);
3772 create_index_cmd = BCON_NEW ("createIndexes",
3773 KEYVAULT_COLL,
3774 "indexes",
3775 "[",
3776 "{",
3777 "key",
3778 BCON_DOCUMENT (index_keys),
3779 "name",
3780 index_name,
3781 "unique",
3782 BCON_BOOL (true),
3783 "partialFilterExpression",
3784 "{",
3785 "keyAltNames",
3786 "{",
3787 "$exists",
3788 BCON_BOOL (true),
3789 "}",
3790 "}",
3791 "}",
3792 "]");
3793 ret = mongoc_client_command_simple (client,
3794 KEYVAULT_DB,
3795 create_index_cmd,
3796 NULL /* read prefs */,
3797 NULL /* reply */,
3798 &error);
3799
3800 if (!ret) {
3801 goto fail;
3802 }
3803
3804 client_encryption_opts = mongoc_client_encryption_opts_new ();
3805 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3806 kms_providers);
3807 mongoc_client_encryption_opts_set_keyvault_namespace (
3808 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3809
3810 /* Set a mongoc_client_t to use for reading/writing to the key vault. This
3811 * can be the same mongoc_client_t used by the main application. */
3812 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3813 client);
3814 client_encryption =
3815 mongoc_client_encryption_new (client_encryption_opts, &error);
3816 if (!client_encryption) {
3817 goto fail;
3818 }
3819
3820 /* Create a new data key for the encryptedField.
3821 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3822 */
3823 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3824 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3825 datakey_opts, keyaltnames, 1);
3826 if (!mongoc_client_encryption_create_datakey (
3827 client_encryption, "local", datakey_opts, &datakey_id, &error)) {
3828 goto fail;
3829 }
3830
3831 /* Explicitly encrypt a field */
3832 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
3833 mongoc_client_encryption_encrypt_opts_set_algorithm (
3834 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
3835 mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id);
3836 to_encrypt.value_type = BSON_TYPE_UTF8;
3837 to_encrypt.value.v_utf8.str = "123456789";
3838 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
3839
3840 ret = mongoc_client_encryption_encrypt (
3841 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
3842 if (!ret) {
3843 goto fail;
3844 }
3845
3846 to_insert = bson_new ();
3847 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
3848 ret = mongoc_collection_insert_one (
3849 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3850 if (!ret) {
3851 goto fail;
3852 }
3853
3854 printf ("encrypted document: ");
3855 if (!print_one_document (coll, &error)) {
3856 goto fail;
3857 }
3858 printf ("\n");
3859
3860 /* Explicitly decrypt a field */
3861 ret = mongoc_client_encryption_decrypt (
3862 client_encryption, &encrypted_field, &decrypted, &error);
3863 if (!ret) {
3864 goto fail;
3865 }
3866 printf ("decrypted value: %s\n", decrypted.value.v_utf8.str);
3867
3868 exit_status = EXIT_SUCCESS;
3869 fail:
3870 if (error.code) {
3871 fprintf (stderr, "error: %s\n", error.message);
3872 }
3873
3874 bson_free (local_masterkey);
3875 bson_destroy (kms_providers);
3876 mongoc_collection_destroy (keyvault_coll);
3877 bson_destroy (index_keys);
3878 bson_free (index_name);
3879 bson_destroy (create_index_cmd);
3880 mongoc_collection_destroy (coll);
3881 mongoc_client_destroy (client);
3882 bson_destroy (to_insert);
3883 bson_destroy (schema);
3884 bson_destroy (create_cmd);
3885 bson_destroy (create_cmd_opts);
3886 mongoc_write_concern_destroy (wc);
3887 mongoc_client_encryption_destroy (client_encryption);
3888 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3889 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3890 bson_value_destroy (&encrypted_field);
3891 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
3892 bson_value_destroy (&decrypted);
3893 bson_value_destroy (&datakey_id);
3894
3895 mongoc_cleanup ();
3896 return exit_status;
3897 }
3898
3899
3900 Explicit Encryption with Automatic Decryption
3901 Although automatic encryption requires MongoDB 4.2 enterprise or a Mon‐
3902 goDB 4.2 Atlas cluster, automatic decryption is supported for all
3903 users. To configure automatic decryption without automatic encryption
3904 set bypass_auto_encryption=True in mongoc_auto_encryption_opts_t:
3905
3906 client-side-encryption-auto-decryption.c
3907
3908 #include <mongoc/mongoc.h>
3909 #include <stdio.h>
3910 #include <stdlib.h>
3911
3912 #include "client-side-encryption-helpers.h"
3913
3914 /* This example demonstrates how to set up automatic decryption without
3915 * automatic encryption using the community version of MongoDB */
3916 int
3917 main (void)
3918 {
3919 /* The collection used to store the encryption data keys. */
3920 #define KEYVAULT_DB "encryption"
3921 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3922 /* The collection used to store the encrypted documents in this example. */
3923 #define ENCRYPTED_DB "test"
3924 #define ENCRYPTED_COLL "coll"
3925
3926 int exit_status = EXIT_FAILURE;
3927 bool ret;
3928 uint8_t *local_masterkey = NULL;
3929 uint32_t local_masterkey_len;
3930 bson_t *kms_providers = NULL;
3931 bson_error_t error = {0};
3932 bson_t *index_keys = NULL;
3933 char *index_name = NULL;
3934 bson_t *create_index_cmd = NULL;
3935 bson_t *schema = NULL;
3936 mongoc_client_t *client = NULL;
3937 mongoc_collection_t *coll = NULL;
3938 mongoc_collection_t *keyvault_coll = NULL;
3939 bson_t *to_insert = NULL;
3940 bson_t *create_cmd = NULL;
3941 bson_t *create_cmd_opts = NULL;
3942 mongoc_write_concern_t *wc = NULL;
3943 mongoc_client_encryption_t *client_encryption = NULL;
3944 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3945 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3946 char *keyaltnames[] = {"mongoc_encryption_example_4"};
3947 bson_value_t datakey_id = {0};
3948 bson_value_t encrypted_field = {0};
3949 bson_value_t to_encrypt = {0};
3950 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3951 bson_value_t decrypted = {0};
3952 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3953 mongoc_client_t *unencrypted_client = NULL;
3954 mongoc_collection_t *unencrypted_coll = NULL;
3955
3956 mongoc_init ();
3957
3958 /* Configure the master key. This must be the same master key that was used
3959 * to create the encryption key. */
3960 local_masterkey =
3961 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3962 if (!local_masterkey || local_masterkey_len != 96) {
3963 fprintf (stderr,
3964 "Specify LOCAL_MASTERKEY environment variable as a "
3965 "secure random 96 byte hex value.\n");
3966 goto fail;
3967 }
3968
3969 kms_providers = BCON_NEW ("local",
3970 "{",
3971 "key",
3972 BCON_BIN (0, local_masterkey, local_masterkey_len),
3973 "}");
3974
3975 client =
3976 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3977 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3978 mongoc_auto_encryption_opts_set_keyvault_namespace (
3979 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3980 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3981 kms_providers);
3982
3983 /* Setting bypass_auto_encryption to true disables automatic encryption but
3984 * keeps the automatic decryption behavior. bypass_auto_encryption will also
3985 * disable spawning mongocryptd */
3986 mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts,
3987 true);
3988
3989 /* Once bypass_auto_encryption is set, community users can enable auto
3990 * encryption on the client. This will, in fact, only perform automatic
3991 * decryption. */
3992 ret = mongoc_client_enable_auto_encryption (
3993 client, auto_encryption_opts, &error);
3994 if (!ret) {
3995 goto fail;
3996 }
3997
3998 /* Now that automatic decryption is on, we can test it by inserting a
3999 * document with an explicitly encrypted value into the collection. When we
4000 * look up the document later, it should be automatically decrypted for us.
4001 */
4002 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
4003
4004 /* Clear old data */
4005 mongoc_collection_drop (coll, NULL);
4006
4007 /* Set up the key vault for this example. */
4008 keyvault_coll =
4009 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
4010 mongoc_collection_drop (keyvault_coll, NULL);
4011
4012 /* Create a unique index to ensure that two data keys cannot share the same
4013 * keyAltName. This is recommended practice for the key vault. */
4014 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
4015 index_name = mongoc_collection_keys_to_index_string (index_keys);
4016 create_index_cmd = BCON_NEW ("createIndexes",
4017 KEYVAULT_COLL,
4018 "indexes",
4019 "[",
4020 "{",
4021 "key",
4022 BCON_DOCUMENT (index_keys),
4023 "name",
4024 index_name,
4025 "unique",
4026 BCON_BOOL (true),
4027 "partialFilterExpression",
4028 "{",
4029 "keyAltNames",
4030 "{",
4031 "$exists",
4032 BCON_BOOL (true),
4033 "}",
4034 "}",
4035 "}",
4036 "]");
4037 ret = mongoc_client_command_simple (client,
4038 KEYVAULT_DB,
4039 create_index_cmd,
4040 NULL /* read prefs */,
4041 NULL /* reply */,
4042 &error);
4043
4044 if (!ret) {
4045 goto fail;
4046 }
4047
4048 client_encryption_opts = mongoc_client_encryption_opts_new ();
4049 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
4050 kms_providers);
4051 mongoc_client_encryption_opts_set_keyvault_namespace (
4052 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
4053
4054 /* The key vault client is used for reading to/from the key vault. This can
4055 * be the same mongoc_client_t used by the application. */
4056 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
4057 client);
4058 client_encryption =
4059 mongoc_client_encryption_new (client_encryption_opts, &error);
4060 if (!client_encryption) {
4061 goto fail;
4062 }
4063
4064 /* Create a new data key for the encryptedField.
4065 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
4066 */
4067 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
4068 mongoc_client_encryption_datakey_opts_set_keyaltnames (
4069 datakey_opts, keyaltnames, 1);
4070 ret = mongoc_client_encryption_create_datakey (
4071 client_encryption, "local", datakey_opts, &datakey_id, &error);
4072 if (!ret) {
4073 goto fail;
4074 }
4075
4076 /* Explicitly encrypt a field. */
4077 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
4078 mongoc_client_encryption_encrypt_opts_set_algorithm (
4079 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
4080 mongoc_client_encryption_encrypt_opts_set_keyaltname (
4081 encrypt_opts, "mongoc_encryption_example_4");
4082 to_encrypt.value_type = BSON_TYPE_UTF8;
4083 to_encrypt.value.v_utf8.str = "123456789";
4084 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
4085
4086 ret = mongoc_client_encryption_encrypt (
4087 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
4088 if (!ret) {
4089 goto fail;
4090 }
4091
4092 to_insert = bson_new ();
4093 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
4094 ret = mongoc_collection_insert_one (
4095 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
4096 if (!ret) {
4097 goto fail;
4098 }
4099
4100 /* When we retrieve the document, any encrypted fields will get automatically
4101 * decrypted by the driver. */
4102 printf ("decrypted document: ");
4103 if (!print_one_document (coll, &error)) {
4104 goto fail;
4105 }
4106 printf ("\n");
4107
4108 unencrypted_client =
4109 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
4110 unencrypted_coll = mongoc_client_get_collection (
4111 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
4112
4113 printf ("encrypted document: ");
4114 if (!print_one_document (unencrypted_coll, &error)) {
4115 goto fail;
4116 }
4117 printf ("\n");
4118
4119 exit_status = EXIT_SUCCESS;
4120 fail:
4121 if (error.code) {
4122 fprintf (stderr, "error: %s\n", error.message);
4123 }
4124
4125 bson_free (local_masterkey);
4126 bson_destroy (kms_providers);
4127 mongoc_collection_destroy (keyvault_coll);
4128 bson_destroy (index_keys);
4129 bson_free (index_name);
4130 bson_destroy (create_index_cmd);
4131 mongoc_collection_destroy (coll);
4132 mongoc_client_destroy (client);
4133 bson_destroy (to_insert);
4134 bson_destroy (schema);
4135 bson_destroy (create_cmd);
4136 bson_destroy (create_cmd_opts);
4137 mongoc_write_concern_destroy (wc);
4138 mongoc_client_encryption_destroy (client_encryption);
4139 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
4140 mongoc_client_encryption_opts_destroy (client_encryption_opts);
4141 bson_value_destroy (&encrypted_field);
4142 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
4143 bson_value_destroy (&decrypted);
4144 bson_value_destroy (&datakey_id);
4145 mongoc_collection_destroy (unencrypted_coll);
4146 mongoc_client_destroy (unencrypted_client);
4147 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
4148
4149 mongoc_cleanup ();
4150 return exit_status;
4151 }
4152
4153
4155 MongoDB, Inc
4156
4158 2017-present, MongoDB, Inc
4159
4160
4161
4162
41631.23.1 Oct 20, 2022 MONGOC_GUIDES(3)