1MONGOC_GUIDES(3) libmongoc MONGOC_GUIDES(3)
2
3
4
6 mongoc_guides - Guides
7
9 Configuration with URI options
10 Enable TLS by including tls=true the URI.
11
12 mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
13 mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
14
15 mongoc_client_t *client = mongoc_client_new_from_uri (uri);
16
17 The following URI options may be used to further configure TLS:
18
19 ┌────────────────────┬─────────────────────┬─────────────────────┐
20 │Constant │ Key │ Description │
21 ├────────────────────┼─────────────────────┼─────────────────────┤
22 │MONGOC_URI_TLS │ tls │ {true|false}, indi‐ │
23 │ │ │ cating if TLS must │
24 │ │ │ be used. │
25 ├────────────────────┼─────────────────────┼─────────────────────┤
26 │MONGOC_URI_TLSCER‐ │ tlscertificatekey‐ │ Path to PEM format‐ │
27 │TIFICATEKEYFILE │ file │ ted Private Key, │
28 │ │ │ with its Public │
29 │ │ │ Certificate con‐ │
30 │ │ │ catenated at the │
31 │ │ │ end. │
32 ├────────────────────┼─────────────────────┼─────────────────────┤
33 │MONGOC_URI_TLSCER‐ │ tlscertificatekey‐ │ The password, if │
34 │TIFICATEKEYPASSWORD │ password │ any, to use to │
35 │ │ │ unlock encrypted │
36 │ │ │ Private Key. │
37 ├────────────────────┼─────────────────────┼─────────────────────┤
38 │MON‐ │ tlscafile │ One, or a bundle │
39 │GOC_URI_TLSCAFILE │ │ of, Certificate │
40 │ │ │ Authorities 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 │
56 │ │ │ issued 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 MON‐ │
75 │ │ │ GOC_URI_TLSALLOWIN‐ │
76 │ │ │ VALIDHOSTNAMES. │
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 │
86 │POINTCHECK │ │ responder endpoints │
87 │ │ │ should not be │
88 │ │ │ requested 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
122 authority specified by --tlsCAFile, or an authority trusted by the
123 native 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
151 potentially 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
197 revokes the server's certificate, the certificate is considered
198 revoked (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
204 libressl.
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
256 revokes 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.)
266 native 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
591 enabled, 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
667 address 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
674 attempted 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
730 options.
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 │ │
768 │ │ remain 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 │ │
777 │ │ acknowledgement, │ │
778 │ │ before 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
806 responded or timed out. Put another way, in single-threaded mode the C
807 Driver fans out to begin all checks concurrently, then fans in once all
808 checks have completed or timed out. Once the scan completes, the client
809 executes your program's operation and returns.
810
811 In single mode, the client re-scans the server topology roughly once
812 per minute. If more than a minute has elapsed since the previous scan,
813 the next operation on the client will block while the client completes
814 its scan. This interval is configurable with heartbeatFrequencyMS in
815 the connection string. (See mongoc_uri_t.)
816
817 A single client opens one connection per server in your topology: these
818 connections are used both for scanning the topology and performing nor‐
819 mal operations.
820
821 Pooled Mode
822 To activate pooled mode, create a mongoc_client_pool_t:
823
824 mongoc_uri_t *uri = mongoc_uri_new (
825 "mongodb://hostA,hostB/?replicaSet=my_rs");
826
827 mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
828
829 When your program first calls mongoc_client_pool_pop, the pool launches
830 monitoring threads in the background. Monitoring threads independently
831 connect to all servers in the connection string. As monitoring threads
832 receive ismaster responses from the servers, they update the shared
833 view of the server topology. Additional monitoring threads and connec‐
834 tions are created as new servers are discovered. Monitoring threads are
835 terminated when servers are removed from the shared view of the server
836 topology.
837
838 Each thread that executes MongoDB operations must check out a client
839 from the pool:
840
841 mongoc_client_t *client = mongoc_client_pool_pop (pool);
842
843 /* use the client for operations ... */
844
845 mongoc_client_pool_push (pool, client);
846
847 The mongoc_client_t object is not thread-safe, only the mon‐
848 goc_client_pool_t is.
849
850 When the driver is in pooled mode, your program's operations are
851 unblocked as soon as monitoring discovers a usable server. For example,
852 if a thread in your program is waiting to execute an "insert" on the
853 primary, it is unblocked as soon as the primary is discovered, rather
854 than waiting for all secondaries to be checked as well.
855
856 The pool opens one connection per server for monitoring, and each
857 client opens its own connection to each server it uses for application
858 operations. Background monitoring threads re-scan servers independently
859 roughly every 10 seconds. This interval is configurable with heartbeat‐
860 FrequencyMS in the connection string. (See mongoc_uri_t.)
861
862 The connection string can also specify waitQueueTimeoutMS to limit the
863 time that mongoc_client_pool_pop will wait for a client from the pool.
864 (See mongoc_uri_t.) If waitQueueTimeoutMS is specified, then it is
865 necessary to confirm that a client was actually returned:
866
867 mongoc_uri_t *uri = mongoc_uri_new (
868 "mongodb://hostA,hostB/?replicaSet=my_rs&waitQueueTimeoutMS=1000");
869
870 mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
871
872 mongoc_client_t *client = mongoc_client_pool_pop (pool);
873
874 if (client) {
875 /* use the client for operations ... */
876
877 mongoc_client_pool_push (pool, client);
878 } else {
879 /* take appropriate action for a timeout */
880 }
881
882 See connection_pool_options to configure pool size and behavior, and
883 see mongoc_client_pool_t for an extended example of a multi-threaded
884 program that uses the driver in pooled mode.
885
887 Handling Cursor Failures
888 Cursors exist on a MongoDB server. However, the mongoc_cursor_t struc‐
889 ture gives the local process a handle to the cursor. It is possible for
890 errors to occur on the server while iterating a cursor on the client.
891 Even a network partition may occur. This means that applications should
892 be robust in handling cursor failures.
893
894 While iterating cursors, you should check to see if an error has
895 occurred. See the following example for how to robustly check for
896 errors.
897
898 static void
899 print_all_documents (mongoc_collection_t *collection)
900 {
901 mongoc_cursor_t *cursor;
902 const bson_t *doc;
903 bson_error_t error;
904 bson_t query = BSON_INITIALIZER;
905 char *str;
906
907 cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);
908
909 while (mongoc_cursor_next (cursor, &doc)) {
910 str = bson_as_canonical_extended_json (doc, NULL);
911 printf ("%s\n", str);
912 bson_free (str);
913 }
914
915 if (mongoc_cursor_error (cursor, &error)) {
916 fprintf (stderr, "Failed to iterate all documents: %s\n", error.message);
917 }
918
919 mongoc_cursor_destroy (cursor);
920 }
921
922 Destroying Server-Side Cursors
923 The MongoDB C driver will automatically destroy a server-side cursor
924 when mongoc_cursor_destroy() is called. Failure to call this function
925 when done with a cursor will leak memory client side as well as consume
926 extra memory server side. If the cursor was configured to never time‐
927 out, it will become a memory leak on the server.
928
929 Tailable Cursors
930 Tailable cursors are cursors that remain open even after they've
931 returned a final result. This way, if more documents are added to a
932 collection (i.e., to the cursor's result set), then you can continue to
933 call mongoc_cursor_next() to retrieve those additional results.
934
935 Here's a complete test case that demonstrates the use of tailable cur‐
936 sors.
937
938 NOTE:
939 Tailable cursors are for capped collections only.
940
941 An example to tail the oplog from a replica set.
942
943 mongoc-tail.c
944
945 #include <bson/bson.h>
946 #include <mongoc/mongoc.h>
947 #include <stdio.h>
948 #include <stdlib.h>
949
950 #ifdef _WIN32
951 #define sleep(_n) Sleep ((_n) *1000)
952 #endif
953
954
955 static void
956 print_bson (const bson_t *b)
957 {
958 char *str;
959
960 str = bson_as_canonical_extended_json (b, NULL);
961 fprintf (stdout, "%s\n", str);
962 bson_free (str);
963 }
964
965
966 static mongoc_cursor_t *
967 query_collection (mongoc_collection_t *collection, uint32_t last_time)
968 {
969 mongoc_cursor_t *cursor;
970 bson_t query;
971 bson_t gt;
972 bson_t opts;
973
974 BSON_ASSERT (collection);
975
976 bson_init (&query);
977 BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", >);
978 BSON_APPEND_TIMESTAMP (>, "$gt", last_time, 0);
979 bson_append_document_end (&query, >);
980
981 bson_init (&opts);
982 BSON_APPEND_BOOL (&opts, "tailable", true);
983 BSON_APPEND_BOOL (&opts, "awaitData", true);
984
985 cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL);
986
987 bson_destroy (&query);
988 bson_destroy (&opts);
989
990 return cursor;
991 }
992
993
994 static void
995 tail_collection (mongoc_collection_t *collection)
996 {
997 mongoc_cursor_t *cursor;
998 uint32_t last_time;
999 const bson_t *doc;
1000 bson_error_t error;
1001 bson_iter_t iter;
1002
1003 BSON_ASSERT (collection);
1004
1005 last_time = (uint32_t) time (NULL);
1006
1007 while (true) {
1008 cursor = query_collection (collection, last_time);
1009 while (!mongoc_cursor_error (cursor, &error) &&
1010 mongoc_cursor_more (cursor)) {
1011 if (mongoc_cursor_next (cursor, &doc)) {
1012 if (bson_iter_init_find (&iter, doc, "ts") &&
1013 BSON_ITER_HOLDS_TIMESTAMP (&iter)) {
1014 bson_iter_timestamp (&iter, &last_time, NULL);
1015 }
1016 print_bson (doc);
1017 }
1018 }
1019 if (mongoc_cursor_error (cursor, &error)) {
1020 if (error.domain == MONGOC_ERROR_SERVER) {
1021 fprintf (stderr, "%s\n", error.message);
1022 exit (1);
1023 }
1024 }
1025
1026 mongoc_cursor_destroy (cursor);
1027 sleep (1);
1028 }
1029 }
1030
1031
1032 int
1033 main (int argc, char *argv[])
1034 {
1035 mongoc_collection_t *collection;
1036 mongoc_client_t *client;
1037 mongoc_uri_t *uri;
1038 bson_error_t error;
1039
1040 if (argc != 2) {
1041 fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]);
1042 return EXIT_FAILURE;
1043 }
1044
1045 mongoc_init ();
1046
1047 uri = mongoc_uri_new_with_error (argv[1], &error);
1048 if (!uri) {
1049 fprintf (stderr,
1050 "failed to parse URI: %s\n"
1051 "error message: %s\n",
1052 argv[1],
1053 error.message);
1054 return EXIT_FAILURE;
1055 }
1056
1057 client = mongoc_client_new_from_uri (uri);
1058 if (!client) {
1059 return EXIT_FAILURE;
1060 }
1061
1062 mongoc_client_set_error_api (client, 2);
1063
1064 collection = mongoc_client_get_collection (client, "local", "oplog.rs");
1065
1066 tail_collection (collection);
1067
1068 mongoc_collection_destroy (collection);
1069 mongoc_uri_destroy (uri);
1070 mongoc_client_destroy (client);
1071
1072 return EXIT_SUCCESS;
1073 }
1074
1075
1076 Let's compile and run this example against a replica set to see updates
1077 as they are made.
1078
1079 $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0)
1080 $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet
1081 {
1082 "h" : -8458503739429355503,
1083 "ns" : "test.test",
1084 "o" : {
1085 "_id" : {
1086 "$oid" : "5372ab0a25164be923d10d50"
1087 }
1088 },
1089 "op" : "i",
1090 "ts" : {
1091 "$timestamp" : {
1092 "i" : 1,
1093 "t" : 1400023818
1094 }
1095 },
1096 "v" : 2
1097 }
1098
1099 The line of output is a sample from performing db.test.insert({}) from
1100 the mongo shell on the replica set.
1101
1102 See also mongoc_cursor_set_max_await_time_ms.
1103
1105 This tutorial explains how to take advantage of MongoDB C driver bulk
1106 write operation features. Executing write operations in batches reduces
1107 the number of network round trips, increasing write throughput.
1108
1109 Bulk Insert
1110 First we need to fetch a bulk operation handle from the mongoc_collec‐
1111 tion_t.
1112
1113 mongoc_bulk_operation_t *bulk =
1114 mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1115
1116 We can now start inserting documents to the bulk operation. These will
1117 be buffered until we execute the operation.
1118
1119 The bulk operation will coalesce insertions as a single batch for each
1120 consecutive call to mongoc_bulk_operation_insert(). This creates a
1121 pipelined effect when possible.
1122
1123 To execute the bulk operation and receive the result we call mon‐
1124 goc_bulk_operation_execute().
1125
1126 bulk1.c
1127
1128 #include <assert.h>
1129 #include <mongoc/mongoc.h>
1130 #include <stdio.h>
1131
1132 static void
1133 bulk1 (mongoc_collection_t *collection)
1134 {
1135 mongoc_bulk_operation_t *bulk;
1136 bson_error_t error;
1137 bson_t *doc;
1138 bson_t reply;
1139 char *str;
1140 bool ret;
1141 int i;
1142
1143 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1144
1145 for (i = 0; i < 10000; i++) {
1146 doc = BCON_NEW ("i", BCON_INT32 (i));
1147 mongoc_bulk_operation_insert (bulk, doc);
1148 bson_destroy (doc);
1149 }
1150
1151 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1152
1153 str = bson_as_canonical_extended_json (&reply, NULL);
1154 printf ("%s\n", str);
1155 bson_free (str);
1156
1157 if (!ret) {
1158 fprintf (stderr, "Error: %s\n", error.message);
1159 }
1160
1161 bson_destroy (&reply);
1162 mongoc_bulk_operation_destroy (bulk);
1163 }
1164
1165 int
1166 main (int argc, char *argv[])
1167 {
1168 mongoc_client_t *client;
1169 mongoc_collection_t *collection;
1170 const char *uri_string = "mongodb://localhost/?appname=bulk1-example";
1171 mongoc_uri_t *uri;
1172 bson_error_t error;
1173
1174 mongoc_init ();
1175
1176 uri = mongoc_uri_new_with_error (uri_string, &error);
1177 if (!uri) {
1178 fprintf (stderr,
1179 "failed to parse URI: %s\n"
1180 "error message: %s\n",
1181 uri_string,
1182 error.message);
1183 return EXIT_FAILURE;
1184 }
1185
1186 client = mongoc_client_new_from_uri (uri);
1187 if (!client) {
1188 return EXIT_FAILURE;
1189 }
1190
1191 mongoc_client_set_error_api (client, 2);
1192 collection = mongoc_client_get_collection (client, "test", "test");
1193
1194 bulk1 (collection);
1195
1196 mongoc_uri_destroy (uri);
1197 mongoc_collection_destroy (collection);
1198 mongoc_client_destroy (client);
1199
1200 mongoc_cleanup ();
1201
1202 return EXIT_SUCCESS;
1203 }
1204
1205
1206 Example reply document:
1207
1208 {"nInserted" : 10000,
1209 "nMatched" : 0,
1210 "nModified" : 0,
1211 "nRemoved" : 0,
1212 "nUpserted" : 0,
1213 "writeErrors" : []
1214 "writeConcernErrors" : [] }
1215
1216 Mixed Bulk Write Operations
1217 MongoDB C driver also supports executing mixed bulk write operations. A
1218 batch of insert, update, and remove operations can be executed together
1219 using the bulk write operations API.
1220
1221 Ordered Bulk Write Operations
1222 Ordered bulk write operations are batched and sent to the server in the
1223 order provided for serial execution. The reply document describes the
1224 type and count of operations performed.
1225
1226 bulk2.c
1227
1228 #include <assert.h>
1229 #include <mongoc/mongoc.h>
1230 #include <stdio.h>
1231
1232 static void
1233 bulk2 (mongoc_collection_t *collection)
1234 {
1235 mongoc_bulk_operation_t *bulk;
1236 bson_error_t error;
1237 bson_t *query;
1238 bson_t *doc;
1239 bson_t *opts;
1240 bson_t reply;
1241 char *str;
1242 bool ret;
1243 int i;
1244
1245 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1246
1247 /* Remove everything */
1248 query = bson_new ();
1249 mongoc_bulk_operation_remove (bulk, query);
1250 bson_destroy (query);
1251
1252 /* Add a few documents */
1253 for (i = 1; i < 4; i++) {
1254 doc = BCON_NEW ("_id", BCON_INT32 (i));
1255 mongoc_bulk_operation_insert (bulk, doc);
1256 bson_destroy (doc);
1257 }
1258
1259 /* {_id: 1} => {$set: {foo: "bar"}} */
1260 query = BCON_NEW ("_id", BCON_INT32 (1));
1261 doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}");
1262 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, NULL, &error);
1263 bson_destroy (query);
1264 bson_destroy (doc);
1265
1266 /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */
1267 opts = BCON_NEW ("upsert", BCON_BOOL (true));
1268 query = BCON_NEW ("_id", BCON_INT32 (4));
1269 doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}");
1270 mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, opts, &error);
1271 bson_destroy (query);
1272 bson_destroy (doc);
1273 bson_destroy (opts);
1274
1275 /* replace {j:1} with {j:2} */
1276 query = BCON_NEW ("j", BCON_INT32 (1));
1277 doc = BCON_NEW ("j", BCON_INT32 (2));
1278 mongoc_bulk_operation_replace_one_with_opts (bulk, query, doc, NULL, &error);
1279 bson_destroy (query);
1280 bson_destroy (doc);
1281
1282 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1283
1284 str = bson_as_canonical_extended_json (&reply, NULL);
1285 printf ("%s\n", str);
1286 bson_free (str);
1287
1288 if (!ret) {
1289 printf ("Error: %s\n", error.message);
1290 }
1291
1292 bson_destroy (&reply);
1293 mongoc_bulk_operation_destroy (bulk);
1294 }
1295
1296 int
1297 main (int argc, char *argv[])
1298 {
1299 mongoc_client_t *client;
1300 mongoc_collection_t *collection;
1301 const char *uri_string = "mongodb://localhost/?appname=bulk2-example";
1302 mongoc_uri_t *uri;
1303 bson_error_t error;
1304
1305 mongoc_init ();
1306
1307 uri = mongoc_uri_new_with_error (uri_string, &error);
1308 if (!uri) {
1309 fprintf (stderr,
1310 "failed to parse URI: %s\n"
1311 "error message: %s\n",
1312 uri_string,
1313 error.message);
1314 return EXIT_FAILURE;
1315 }
1316
1317 client = mongoc_client_new_from_uri (uri);
1318 if (!client) {
1319 return EXIT_FAILURE;
1320 }
1321
1322 mongoc_client_set_error_api (client, 2);
1323 collection = mongoc_client_get_collection (client, "test", "test");
1324
1325 bulk2 (collection);
1326
1327 mongoc_uri_destroy (uri);
1328 mongoc_collection_destroy (collection);
1329 mongoc_client_destroy (client);
1330
1331 mongoc_cleanup ();
1332
1333 return EXIT_SUCCESS;
1334 }
1335
1336
1337 Example reply document:
1338
1339 { "nInserted" : 3,
1340 "nMatched" : 2,
1341 "nModified" : 2,
1342 "nRemoved" : 10000,
1343 "nUpserted" : 1,
1344 "upserted" : [{"index" : 5, "_id" : 4}],
1345 "writeErrors" : []
1346 "writeConcernErrors" : [] }
1347
1348 The index field in the upserted array is the 0-based index of the
1349 upsert operation; in this example, the sixth operation of the overall
1350 bulk operation was an upsert, so its index is 5.
1351
1352 Unordered Bulk Write Operations
1353 Unordered bulk write operations are batched and sent to the server in
1354 arbitrary order where they may be executed in parallel. Any errors that
1355 occur are reported after all operations are attempted.
1356
1357 In the next example the first and third operations fail due to the
1358 unique constraint on _id. Since we are doing unordered execution the
1359 second and fourth operations succeed.
1360
1361 bulk3.c
1362
1363 #include <assert.h>
1364 #include <mongoc/mongoc.h>
1365 #include <stdio.h>
1366
1367 static void
1368 bulk3 (mongoc_collection_t *collection)
1369 {
1370 bson_t opts = BSON_INITIALIZER;
1371 mongoc_bulk_operation_t *bulk;
1372 bson_error_t error;
1373 bson_t *query;
1374 bson_t *doc;
1375 bson_t reply;
1376 char *str;
1377 bool ret;
1378
1379 /* false indicates unordered */
1380 BSON_APPEND_BOOL (&opts, "ordered", false);
1381 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1382 bson_destroy (&opts);
1383
1384 /* Add a document */
1385 doc = BCON_NEW ("_id", BCON_INT32 (1));
1386 mongoc_bulk_operation_insert (bulk, doc);
1387 bson_destroy (doc);
1388
1389 /* remove {_id: 2} */
1390 query = BCON_NEW ("_id", BCON_INT32 (2));
1391 mongoc_bulk_operation_remove_one (bulk, query);
1392 bson_destroy (query);
1393
1394 /* insert {_id: 3} */
1395 doc = BCON_NEW ("_id", BCON_INT32 (3));
1396 mongoc_bulk_operation_insert (bulk, doc);
1397 bson_destroy (doc);
1398
1399 /* replace {_id:4} {'i': 1} */
1400 query = BCON_NEW ("_id", BCON_INT32 (4));
1401 doc = BCON_NEW ("i", BCON_INT32 (1));
1402 mongoc_bulk_operation_replace_one (bulk, query, doc, false);
1403 bson_destroy (query);
1404 bson_destroy (doc);
1405
1406 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1407
1408 str = bson_as_canonical_extended_json (&reply, NULL);
1409 printf ("%s\n", str);
1410 bson_free (str);
1411
1412 if (!ret) {
1413 printf ("Error: %s\n", error.message);
1414 }
1415
1416 bson_destroy (&reply);
1417 mongoc_bulk_operation_destroy (bulk);
1418 bson_destroy (&opts);
1419 }
1420
1421 int
1422 main (int argc, char *argv[])
1423 {
1424 mongoc_client_t *client;
1425 mongoc_collection_t *collection;
1426 const char *uri_string = "mongodb://localhost/?appname=bulk3-example";
1427 mongoc_uri_t *uri;
1428 bson_error_t error;
1429
1430 mongoc_init ();
1431
1432 uri = mongoc_uri_new_with_error (uri_string, &error);
1433 if (!uri) {
1434 fprintf (stderr,
1435 "failed to parse URI: %s\n"
1436 "error message: %s\n",
1437 uri_string,
1438 error.message);
1439 return EXIT_FAILURE;
1440 }
1441
1442 client = mongoc_client_new_from_uri (uri);
1443 if (!client) {
1444 return EXIT_FAILURE;
1445 }
1446
1447 mongoc_client_set_error_api (client, 2);
1448 collection = mongoc_client_get_collection (client, "test", "test");
1449
1450 bulk3 (collection);
1451
1452 mongoc_uri_destroy (uri);
1453 mongoc_collection_destroy (collection);
1454 mongoc_client_destroy (client);
1455
1456 mongoc_cleanup ();
1457
1458 return EXIT_SUCCESS;
1459 }
1460
1461
1462 Example reply document:
1463
1464 { "nInserted" : 0,
1465 "nMatched" : 1,
1466 "nModified" : 1,
1467 "nRemoved" : 1,
1468 "nUpserted" : 0,
1469 "writeErrors" : [
1470 { "index" : 0,
1471 "code" : 11000,
1472 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" },
1473 { "index" : 2,
1474 "code" : 11000,
1475 "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ],
1476 "writeConcernErrors" : [] }
1477
1478 Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }
1479
1480 The bson_error_t domain is MONGOC_ERROR_COMMAND and its code is 11000.
1481
1482 Bulk Operation Bypassing Document Validation
1483 This feature is only available when using MongoDB 3.2 and later.
1484
1485 By default bulk operations are validated against the schema, if any is
1486 defined. In certain cases however it may be necessary to bypass the
1487 document validation.
1488
1489 bulk5.c
1490
1491 #include <assert.h>
1492 #include <mongoc/mongoc.h>
1493 #include <stdio.h>
1494
1495 static void
1496 bulk5_fail (mongoc_collection_t *collection)
1497 {
1498 mongoc_bulk_operation_t *bulk;
1499 bson_error_t error;
1500 bson_t *doc;
1501 bson_t reply;
1502 char *str;
1503 bool ret;
1504
1505 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1506
1507 /* Two inserts */
1508 doc = BCON_NEW ("_id", BCON_INT32 (31));
1509 mongoc_bulk_operation_insert (bulk, doc);
1510 bson_destroy (doc);
1511
1512 doc = BCON_NEW ("_id", BCON_INT32 (32));
1513 mongoc_bulk_operation_insert (bulk, doc);
1514 bson_destroy (doc);
1515
1516 /* The above documents do not comply to the schema validation rules
1517 * we created previously, so this will result in an error */
1518 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1519
1520 str = bson_as_canonical_extended_json (&reply, NULL);
1521 printf ("%s\n", str);
1522 bson_free (str);
1523
1524 if (!ret) {
1525 printf ("Error: %s\n", error.message);
1526 }
1527
1528 bson_destroy (&reply);
1529 mongoc_bulk_operation_destroy (bulk);
1530 }
1531
1532 static void
1533 bulk5_success (mongoc_collection_t *collection)
1534 {
1535 mongoc_bulk_operation_t *bulk;
1536 bson_error_t error;
1537 bson_t *doc;
1538 bson_t reply;
1539 char *str;
1540 bool ret;
1541
1542 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1543
1544 /* Allow this document to bypass document validation.
1545 * NOTE: When authentication is enabled, the authenticated user must have
1546 * either the "dbadmin" or "restore" roles to bypass document validation */
1547 mongoc_bulk_operation_set_bypass_document_validation (bulk, true);
1548
1549 /* Two inserts */
1550 doc = BCON_NEW ("_id", BCON_INT32 (31));
1551 mongoc_bulk_operation_insert (bulk, doc);
1552 bson_destroy (doc);
1553
1554 doc = BCON_NEW ("_id", BCON_INT32 (32));
1555 mongoc_bulk_operation_insert (bulk, doc);
1556 bson_destroy (doc);
1557
1558 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1559
1560 str = bson_as_canonical_extended_json (&reply, NULL);
1561 printf ("%s\n", str);
1562 bson_free (str);
1563
1564 if (!ret) {
1565 printf ("Error: %s\n", error.message);
1566 }
1567
1568 bson_destroy (&reply);
1569 mongoc_bulk_operation_destroy (bulk);
1570 }
1571
1572 int
1573 main (int argc, char *argv[])
1574 {
1575 bson_t *options;
1576 bson_error_t error;
1577 mongoc_client_t *client;
1578 mongoc_collection_t *collection;
1579 mongoc_database_t *database;
1580 const char *uri_string = "mongodb://localhost/?appname=bulk5-example";
1581 mongoc_uri_t *uri;
1582
1583 mongoc_init ();
1584
1585 uri = mongoc_uri_new_with_error (uri_string, &error);
1586 if (!uri) {
1587 fprintf (stderr,
1588 "failed to parse URI: %s\n"
1589 "error message: %s\n",
1590 uri_string,
1591 error.message);
1592 return EXIT_FAILURE;
1593 }
1594
1595 client = mongoc_client_new_from_uri (uri);
1596 if (!client) {
1597 return EXIT_FAILURE;
1598 }
1599
1600 mongoc_client_set_error_api (client, 2);
1601 database = mongoc_client_get_database (client, "testasdf");
1602
1603 /* Create schema validator */
1604 options = BCON_NEW (
1605 "validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}");
1606 collection =
1607 mongoc_database_create_collection (database, "collname", options, &error);
1608
1609 if (collection) {
1610 bulk5_fail (collection);
1611 bulk5_success (collection);
1612 mongoc_collection_destroy (collection);
1613 } else {
1614 fprintf (stderr, "Couldn't create collection: '%s'\n", error.message);
1615 }
1616
1617 bson_free (options);
1618 mongoc_uri_destroy (uri);
1619 mongoc_database_destroy (database);
1620 mongoc_client_destroy (client);
1621
1622 mongoc_cleanup ();
1623
1624 return EXIT_SUCCESS;
1625 }
1626
1627
1628 Running the above example will result in:
1629
1630 { "nInserted" : 0,
1631 "nMatched" : 0,
1632 "nModified" : 0,
1633 "nRemoved" : 0,
1634 "nUpserted" : 0,
1635 "writeErrors" : [
1636 { "index" : 0,
1637 "code" : 121,
1638 "errmsg" : "Document failed validation" } ] }
1639
1640 Error: Document failed validation
1641
1642 { "nInserted" : 2,
1643 "nMatched" : 0,
1644 "nModified" : 0,
1645 "nRemoved" : 0,
1646 "nUpserted" : 0,
1647 "writeErrors" : [] }
1648
1649 The bson_error_t domain is MONGOC_ERROR_COMMAND.
1650
1651 Bulk Operation Write Concerns
1652 By default bulk operations are executed with the write_concern of the
1653 collection they are executed against. A custom write concern can be
1654 passed to the mongoc_collection_create_bulk_operation_with_opts()
1655 method. Write concern errors (e.g. wtimeout) will be reported after all
1656 operations are attempted, regardless of execution order.
1657
1658 bulk4.c
1659
1660 #include <assert.h>
1661 #include <mongoc/mongoc.h>
1662 #include <stdio.h>
1663
1664 static void
1665 bulk4 (mongoc_collection_t *collection)
1666 {
1667 bson_t opts = BSON_INITIALIZER;
1668 mongoc_write_concern_t *wc;
1669 mongoc_bulk_operation_t *bulk;
1670 bson_error_t error;
1671 bson_t *doc;
1672 bson_t reply;
1673 char *str;
1674 bool ret;
1675
1676 wc = mongoc_write_concern_new ();
1677 mongoc_write_concern_set_w (wc, 4);
1678 mongoc_write_concern_set_wtimeout_int64 (wc, 100); /* milliseconds */
1679 mongoc_write_concern_append (wc, &opts);
1680
1681 bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1682
1683 /* Two inserts */
1684 doc = BCON_NEW ("_id", BCON_INT32 (10));
1685 mongoc_bulk_operation_insert (bulk, doc);
1686 bson_destroy (doc);
1687
1688 doc = BCON_NEW ("_id", BCON_INT32 (11));
1689 mongoc_bulk_operation_insert (bulk, doc);
1690 bson_destroy (doc);
1691
1692 ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1693
1694 str = bson_as_canonical_extended_json (&reply, NULL);
1695 printf ("%s\n", str);
1696 bson_free (str);
1697
1698 if (!ret) {
1699 printf ("Error: %s\n", error.message);
1700 }
1701
1702 bson_destroy (&reply);
1703 mongoc_bulk_operation_destroy (bulk);
1704 mongoc_write_concern_destroy (wc);
1705 bson_destroy (&opts);
1706 }
1707
1708 int
1709 main (int argc, char *argv[])
1710 {
1711 mongoc_client_t *client;
1712 mongoc_collection_t *collection;
1713 const char *uri_string = "mongodb://localhost/?appname=bulk4-example";
1714 mongoc_uri_t *uri;
1715 bson_error_t error;
1716
1717 mongoc_init ();
1718
1719 uri = mongoc_uri_new_with_error (uri_string, &error);
1720 if (!uri) {
1721 fprintf (stderr,
1722 "failed to parse URI: %s\n"
1723 "error message: %s\n",
1724 uri_string,
1725 error.message);
1726 return EXIT_FAILURE;
1727 }
1728
1729 client = mongoc_client_new_from_uri (uri);
1730 if (!client) {
1731 return EXIT_FAILURE;
1732 }
1733
1734 mongoc_client_set_error_api (client, 2);
1735 collection = mongoc_client_get_collection (client, "test", "test");
1736
1737 bulk4 (collection);
1738
1739 mongoc_uri_destroy (uri);
1740 mongoc_collection_destroy (collection);
1741 mongoc_client_destroy (client);
1742
1743 mongoc_cleanup ();
1744
1745 return EXIT_SUCCESS;
1746 }
1747
1748
1749 Example reply document and error message:
1750
1751 { "nInserted" : 2,
1752 "nMatched" : 0,
1753 "nModified" : 0,
1754 "nRemoved" : 0,
1755 "nUpserted" : 0,
1756 "writeErrors" : [],
1757 "writeConcernErrors" : [
1758 { "code" : 64,
1759 "errmsg" : "waiting for replication timed out" }
1760 ] }
1761
1762 Error: waiting for replication timed out
1763
1764 The bson_error_t domain is MONGOC_ERROR_WRITE_CONCERN if there are
1765 write concern errors and no write errors. Write errors indicate failed
1766 operations, so they take precedence over write concern errors, which
1767 mean merely that the write concern is not satisfied yet.
1768
1769 Setting Collation Order
1770 This feature is only available when using MongoDB 3.4 and later.
1771
1772 bulk-collation.c
1773
1774 #include <mongoc/mongoc.h>
1775 #include <stdio.h>
1776
1777 static void
1778 bulk_collation (mongoc_collection_t *collection)
1779 {
1780 mongoc_bulk_operation_t *bulk;
1781 bson_t *opts;
1782 bson_t *doc;
1783 bson_t *selector;
1784 bson_t *update;
1785 bson_error_t error;
1786 bson_t reply;
1787 char *str;
1788 uint32_t ret;
1789
1790 /* insert {_id: "one"} and {_id: "One"} */
1791 bulk = mongoc_collection_create_bulk_operation_with_opts (
1792 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 (int argc, char *argv[])
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 (int argc, char *argv[])
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
1997 instance:
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 (int argc, char *argv[])
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
2210 order. 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. mon‐
2364 goc_database_command_simple()). Do not the read command helpers (e.g.
2365 mongoc_database_read_command_with_opts()) because they are considered
2366 retryable read operations. If retryable reads are enabled, those opera‐
2367 tions will retry once on a retryable error, giving undesirable behavior
2368 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
2701 application to the libbson and libmongoc DLLs. This is usually the
2702 right choice. If you want to link statically instead, update your
2703 "Additional Dependencies" list by removing bson-1.0.lib and mon‐
2704 goc-1.0.lib and replacing 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 mongoc_database_write_com‐
2741 mand_with_opts or mongoc_collection_write_command_with_opts. See the
2742 MongoDB Manual entry for the createIndexes command for details.
2743
2744 Example
2745 example-create-indexes.c
2746
2747 /* gcc example-create-indexes.c -o example-create-indexes $(pkg-config --cflags
2748 * --libs libmongoc-1.0) */
2749
2750 /* ./example-create-indexes [CONNECTION_STRING [COLLECTION_NAME]] */
2751
2752 #include <mongoc/mongoc.h>
2753 #include <stdio.h>
2754 #include <stdlib.h>
2755
2756 int
2757 main (int argc, char *argv[])
2758 {
2759 mongoc_client_t *client;
2760 const char *uri_string =
2761 "mongodb://127.0.0.1/?appname=create-indexes-example";
2762 mongoc_uri_t *uri;
2763 mongoc_database_t *db;
2764 const char *collection_name = "test";
2765 bson_t keys;
2766 char *index_name;
2767 bson_t *create_indexes;
2768 bson_t reply;
2769 char *reply_str;
2770 bson_error_t error;
2771 bool r;
2772
2773 mongoc_init ();
2774
2775 if (argc > 1) {
2776 uri_string = argv[1];
2777 }
2778
2779 if (argc > 2) {
2780 collection_name = argv[2];
2781 }
2782
2783 uri = mongoc_uri_new_with_error (uri_string, &error);
2784 if (!uri) {
2785 fprintf (stderr,
2786 "failed to parse URI: %s\n"
2787 "error message: %s\n",
2788 uri_string,
2789 error.message);
2790 return EXIT_FAILURE;
2791 }
2792
2793 client = mongoc_client_new_from_uri (uri);
2794 if (!client) {
2795 return EXIT_FAILURE;
2796 }
2797
2798 mongoc_client_set_error_api (client, 2);
2799 db = mongoc_client_get_database (client, "test");
2800
2801 /* ascending index on field "x" */
2802 bson_init (&keys);
2803 BSON_APPEND_INT32 (&keys, "x", 1);
2804 index_name = mongoc_collection_keys_to_index_string (&keys);
2805 create_indexes = BCON_NEW ("createIndexes",
2806 BCON_UTF8 (collection_name),
2807 "indexes",
2808 "[",
2809 "{",
2810 "key",
2811 BCON_DOCUMENT (&keys),
2812 "name",
2813 BCON_UTF8 (index_name),
2814 "}",
2815 "]");
2816
2817 r = mongoc_database_write_command_with_opts (
2818 db, create_indexes, NULL /* opts */, &reply, &error);
2819
2820 reply_str = bson_as_json (&reply, NULL);
2821 printf ("%s\n", reply_str);
2822
2823 if (!r) {
2824 fprintf (stderr, "Error in createIndexes: %s\n", error.message);
2825 }
2826
2827 bson_free (index_name);
2828 bson_free (reply_str);
2829 bson_destroy (&reply);
2830 bson_destroy (create_indexes);
2831 mongoc_database_destroy (db);
2832 mongoc_uri_destroy (uri);
2833 mongoc_client_destroy (client);
2834
2835 mongoc_cleanup ();
2836
2837 return r ? EXIT_SUCCESS : EXIT_FAILURE;
2838 }
2839
2840
2842 GDB
2843 This repository contains a .gdbinit file that contains helper functions
2844 to aid debugging of data structures. GDB will load this file
2845 automatically if you have added the directory which contains the
2846 .gdbinit file to GDB's auto-load safe-path, and you start GDB from the
2847 directory which holds the .gdbinit file.
2848
2849 You can see the safe-path with show auto-load safe-path on a GDB
2850 prompt. You can configure it by setting it in ~/.gdbinit with:
2851
2852 add-auto-load-safe-path /path/to/mongo-c-driver
2853
2854 If you haven't added the path to your auto-load safe-path, or start GDB
2855 in another directory, load the file with:
2856
2857 source path/to/mongo-c-driver/.gdbinit
2858
2859 The .gdbinit file defines the printbson function, which shows the con‐
2860 tents of a bson_t * variable. If you have a local bson_t, then you
2861 must prefix the variable with a &.
2862
2863 An example GDB session looks like:
2864
2865 (gdb) printbson bson
2866 ALLOC [0x555556cd7310 + 0] (len=475)
2867 {
2868 'bool' : true,
2869 'int32' : NumberInt("42"),
2870 'int64' : NumberLong("3000000042"),
2871 'string' : "Stŕìñg",
2872 'objectId' : ObjectID("5A1442F3122D331C3C6757E1"),
2873 'utcDateTime' : UTCDateTime(1511277299031),
2874 'arrayOfInts' : [
2875 '0' : NumberInt("1"),
2876 '1' : NumberInt("2")
2877 ],
2878 'embeddedDocument' : {
2879 'arrayOfStrings' : [
2880 '0' : "one",
2881 '1' : "two"
2882 ],
2883 'double' : 2.718280,
2884 'notherDoc' : {
2885 'true' : NumberInt("1"),
2886 'false' : false
2887 }
2888 },
2889 'binary' : Binary("02", "3031343532333637"),
2890 'regex' : Regex("@[a-z]+@", "im"),
2891 'null' : null,
2892 'js' : JavaScript("print foo"),
2893 'jsws' : JavaScript("print foo") with scope: {
2894 'f' : NumberInt("42"),
2895 'a' : [
2896 '0' : 3.141593,
2897 '1' : 2.718282
2898 ]
2899 },
2900 'timestamp' : Timestamp(4294967295, 4294967295),
2901 'double' : 3.141593
2902 }
2903
2904 LLDB
2905 This repository also includes a script that customizes LLDB's standard
2906 print command to print a bson_t or bson_t * as JSON:
2907
2908 (lldb) print b
2909 (bson_t) $0 = {"x": 1, "y": 2}
2910
2911 The custom bson command provides more options:
2912
2913 (lldb) bson --verbose b
2914 len=19
2915 flags=INLINE|STATIC
2916 {
2917 "x": 1,
2918 "y": 2
2919 }
2920 (lldb) bson --raw b
2921 '\x13\x00\x00\x00\x10x\x00\x01\x00\x00\x00\x10y\x00\x02\x00\x00\x00\x00'
2922
2923 Type help bson for a list of options.
2924
2925 The script requires a build of libbson with debug symbols, and an
2926 installation of PyMongo. Install PyMongo with:
2927
2928 python -m pip install pymongo
2929
2930 If you see "No module named pip" then you must install pip, then run
2931 the previous command again.
2932
2933 Create a file ~/.lldbinit containing:
2934
2935 command script import /path/to/mongo-c-driver/lldb_bson.py
2936
2937 If you see "bson command installed by lldb_bson" at the beginning of
2938 your LLDB session, you've installed the script correctly.
2939
2941 New in MongoDB 4.2, Client-Side Field Level Encryption (also referred
2942 to as Client-Side Encryption) allows administrators and developers to
2943 encrypt specific data fields in addition to other MongoDB encryption
2944 features.
2945
2946 With Client-Side Encryption, developers can encrypt fields client side
2947 without any server-side configuration or directives. Client-Side
2948 Encryption supports workloads where applications must guarantee that
2949 unauthorized parties, including server administrators, cannot read the
2950 encrypted data.
2951
2952 Automatic encryption, where sensitive fields in commands are encrypted
2953 automatically, requires an Enterprise-only process to do query analy‐
2954 sis.
2955
2956 Installation
2957 libmongocrypt
2958 There is a separate library, libmongocrypt, that must be installed
2959 prior to configuring libmongoc to enable Client-Side Encryption.
2960
2961 libmongocrypt depends on libbson. To build libmongoc with Client-Side
2962 Encryption support you must:
2963
2964 1. Install libbson
2965
2966 2. Build and install libmongocrypt
2967
2968 3. Build libmongoc
2969
2970 To install libbson, follow the instructions to install with a package
2971 manager: Install libbson with a Package Manager or build from source
2972 with cmake (disable building libmongoc with -DENABLE_MONGOC=OFF):
2973
2974 $ cd mongo-c-driver
2975 $ mkdir cmake-build && cd cmake-build
2976 $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGOC=OFF ..
2977 $ cmake --build . --target install
2978
2979 To build and install libmongocrypt, clone the repository and configure
2980 as follows:
2981
2982 $ cd libmongocrypt
2983 $ mkdir cmake-build && cd cmake-build
2984 $ cmake -DENABLE_SHARED_BSON=ON ..
2985 $ cmake --build . --target install
2986
2987 Then, you should be able to build libmongoc with Client-Side Encryp‐
2988 tion.
2989
2990 $ cd mongo-c-driver
2991 $ mkdir cmake-build && cd cmake-build
2992 $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGOC=ON -DENABLE_CLIENT_SIDE_ENCRYPTION=ON ..
2993 $ cmake --build . --target install
2994
2995 mongocryptd
2996 The mongocryptd binary is required for automatic Client-Side Encryption
2997 and is included as a component in the MongoDB Enterprise Server pack‐
2998 age. For detailed installation instructions see the MongoDB documenta‐
2999 tion on mongocryptd.
3000
3001 mongocryptd performs the following:
3002
3003 · Parses the automatic encryption rules specified to the database con‐
3004 nection. If the JSON schema contains invalid automatic encryption
3005 syntax or any document validation syntax, mongocryptd returns an
3006 error.
3007
3008 · Uses the specified automatic encryption rules to mark fields in read
3009 and write operations for encryption.
3010
3011 · Rejects read/write operations that may return unexpected or incorrect
3012 results when applied to an encrypted field. For supported and unsup‐
3013 ported operations, see Read/Write Support with Automatic Field Level
3014 Encryption.
3015
3016 A mongoc_client_t configured with auto encryption will automatically
3017 spawn the mongocryptd process from the application's PATH. Applications
3018 can control the spawning behavior as part of the automatic encryption
3019 options. For example, to set a custom path to the mongocryptd process,
3020 set the mongocryptdSpawnPath with mongoc_auto_encryp‐
3021 tion_opts_set_extra().
3022
3023 bson_t *extra = BCON_NEW ("mongocryptdSpawnPath", "/path/to/mongocryptd");
3024 mongoc_auto_encryption_opts_set_extra (opts, extra);
3025
3026 To control the logging output of mongocryptd pass mongocryptdSpawnArgs
3027 to mongoc_auto_encryption_opts_set_extra():
3028
3029 bson_t *extra = BCON_NEW ("mongocryptdSpawnArgs",
3030 "[", "--logpath=/path/to/mongocryptd.log", "--logappend", "]");
3031 mongoc_auto_encryption_opts_set_extra (opts, extra);
3032
3033 If your application wishes to manage the mongocryptd process manually,
3034 it is possible to disable spawning mongocryptd:
3035
3036 bson_t *extra = BCON_NEW ("mongocryptdBypassSpawn",
3037 BCON_BOOL(true), "mongocryptdURI", "mongodb://localhost:27020");
3038 mongoc_auto_encryption_opts_set_extra (opts, extra);
3039
3040 mongocryptd is only responsible for supporting automatic Client-Side
3041 Encryption in the driver and does not itself perform any encryption or
3042 decryption.
3043
3044 Automatic Client-Side Field Level Encryption
3045 Automatic Client-Side Encryption is enabled by calling mon‐
3046 goc_client_enable_auto_encryption() on a mongoc_client_t. The following
3047 examples show how to set up automatic client-side field level encryp‐
3048 tion using mongoc_client_encryption_t to create a new encryption data
3049 key.
3050
3051 NOTE:
3052 Automatic client-side field level encryption requires MongoDB 4.2
3053 enterprise or a MongoDB 4.2 Atlas cluster. The community version of
3054 the server supports automatic decryption as well as Explicit Encryp‐
3055 tion.
3056
3057 Providing Local Automatic Encryption Rules
3058 The following example shows how to specify automatic encryption rules
3059 using a schema map set with mongoc_auto_encryp‐
3060 tion_opts_set_schema_map(). The automatic encryption rules are
3061 expressed using a strict subset of the JSON Schema syntax.
3062
3063 Supplying a schema map provides more security than relying on JSON
3064 Schemas obtained from the server. It protects against a malicious
3065 server advertising a false JSON Schema, which could trick the client
3066 into sending unencrypted data that should be encrypted.
3067
3068 JSON Schemas supplied in the schema map only apply to configuring auto‐
3069 matic client-side field level encryption. Other validation rules in the
3070 JSON schema will not be enforced by the driver and will result in an
3071 error:
3072
3073 client-side-encryption-schema-map.c
3074
3075 #include <mongoc/mongoc.h>
3076 #include <stdio.h>
3077 #include <stdlib.h>
3078
3079 #include "client-side-encryption-helpers.h"
3080
3081 /* Helper method to create a new data key in the key vault, a schema to use that
3082 * key, and writes the schema to a file for later use. */
3083 static bool
3084 create_schema_file (bson_t *kms_providers,
3085 const char *keyvault_db,
3086 const char *keyvault_coll,
3087 mongoc_client_t *keyvault_client,
3088 bson_error_t *error)
3089 {
3090 mongoc_client_encryption_t *client_encryption = NULL;
3091 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3092 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3093 bson_value_t datakey_id = {0};
3094 char *keyaltnames[] = {"mongoc_encryption_example_1"};
3095 bson_t *schema = NULL;
3096 char *schema_string = NULL;
3097 size_t schema_string_len;
3098 FILE *outfile = NULL;
3099 bool ret = false;
3100
3101 client_encryption_opts = mongoc_client_encryption_opts_new ();
3102 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3103 kms_providers);
3104 mongoc_client_encryption_opts_set_keyvault_namespace (
3105 client_encryption_opts, keyvault_db, keyvault_coll);
3106 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3107 keyvault_client);
3108
3109 client_encryption =
3110 mongoc_client_encryption_new (client_encryption_opts, error);
3111 if (!client_encryption) {
3112 goto fail;
3113 }
3114
3115 /* Create a new data key and json schema for the encryptedField.
3116 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3117 */
3118 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3119 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3120 datakey_opts, keyaltnames, 1);
3121 if (!mongoc_client_encryption_create_datakey (
3122 client_encryption, "local", datakey_opts, &datakey_id, error)) {
3123 goto fail;
3124 }
3125
3126 /* Create a schema describing that "encryptedField" is a string encrypted
3127 * with the newly created data key using deterministic encryption. */
3128 schema = BCON_NEW ("properties",
3129 "{",
3130 "encryptedField",
3131 "{",
3132 "encrypt",
3133 "{",
3134 "keyId",
3135 "[",
3136 BCON_BIN (datakey_id.value.v_binary.subtype,
3137 datakey_id.value.v_binary.data,
3138 datakey_id.value.v_binary.data_len),
3139 "]",
3140 "bsonType",
3141 "string",
3142 "algorithm",
3143 MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3144 "}",
3145 "}",
3146 "}",
3147 "bsonType",
3148 "object");
3149
3150 /* Use canonical JSON so that other drivers and tools will be
3151 * able to parse the MongoDB extended JSON file. */
3152 schema_string = bson_as_canonical_extended_json (schema, &schema_string_len);
3153 outfile = fopen ("jsonSchema.json", "w");
3154 if (0 == fwrite (schema_string, sizeof (char), schema_string_len, outfile)) {
3155 fprintf (stderr, "failed to write to file\n");
3156 goto fail;
3157 }
3158
3159 ret = true;
3160 fail:
3161 mongoc_client_encryption_destroy (client_encryption);
3162 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3163 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3164 bson_free (schema_string);
3165 bson_destroy (schema);
3166 bson_value_destroy (&datakey_id);
3167 if (outfile) {
3168 fclose (outfile);
3169 }
3170 return true;
3171 }
3172
3173 /* This example demonstrates how to use automatic encryption with a client-side
3174 * schema map using the enterprise version of MongoDB */
3175 int
3176 main (int argc, char **argv)
3177 {
3178 /* The collection used to store the encryption data keys. */
3179 #define KEYVAULT_DB "encryption"
3180 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3181 /* The collection used to store the encrypted documents in this example. */
3182 #define ENCRYPTED_DB "test"
3183 #define ENCRYPTED_COLL "coll"
3184
3185 int exit_status = EXIT_FAILURE;
3186 bool ret;
3187 uint8_t *local_masterkey = NULL;
3188 uint32_t local_masterkey_len;
3189 bson_t *kms_providers = NULL;
3190 bson_error_t error = {0};
3191 bson_t *index_keys = NULL;
3192 char *index_name = NULL;
3193 bson_t *create_index_cmd = NULL;
3194 bson_json_reader_t *reader = NULL;
3195 bson_t schema = BSON_INITIALIZER;
3196 bson_t *schema_map = NULL;
3197
3198 /* The MongoClient used to access the key vault (keyvault_namespace). */
3199 mongoc_client_t *keyvault_client = NULL;
3200 mongoc_collection_t *keyvault_coll = NULL;
3201 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3202 mongoc_client_t *client = NULL;
3203 mongoc_collection_t *coll = NULL;
3204 bson_t *to_insert = NULL;
3205 mongoc_client_t *unencrypted_client = NULL;
3206 mongoc_collection_t *unencrypted_coll = NULL;
3207
3208 mongoc_init ();
3209
3210 /* Configure the master key. This must be the same master key that was used
3211 * to create the encryption key. */
3212 local_masterkey =
3213 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3214 if (!local_masterkey || local_masterkey_len != 96) {
3215 fprintf (stderr,
3216 "Specify LOCAL_MASTERKEY environment variable as a "
3217 "secure random 96 byte hex value.\n");
3218 goto fail;
3219 }
3220
3221 kms_providers = BCON_NEW ("local",
3222 "{",
3223 "key",
3224 BCON_BIN (0, local_masterkey, local_masterkey_len),
3225 "}");
3226
3227 /* Set up the key vault for this example. */
3228 keyvault_client = mongoc_client_new (
3229 "mongodb://localhost/?appname=client-side-encryption-keyvault");
3230 keyvault_coll = mongoc_client_get_collection (
3231 keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3232 mongoc_collection_drop (keyvault_coll, NULL);
3233
3234 /* Create a unique index to ensure that two data keys cannot share the same
3235 * keyAltName. This is recommended practice for the key vault. */
3236 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3237 index_name = mongoc_collection_keys_to_index_string (index_keys);
3238 create_index_cmd = BCON_NEW ("createIndexes",
3239 KEYVAULT_COLL,
3240 "indexes",
3241 "[",
3242 "{",
3243 "key",
3244 BCON_DOCUMENT (index_keys),
3245 "name",
3246 index_name,
3247 "unique",
3248 BCON_BOOL (true),
3249 "partialFilterExpression",
3250 "{",
3251 "keyAltNames",
3252 "{",
3253 "$exists",
3254 BCON_BOOL (true),
3255 "}",
3256 "}",
3257 "}",
3258 "]");
3259 ret = mongoc_client_command_simple (keyvault_client,
3260 KEYVAULT_DB,
3261 create_index_cmd,
3262 NULL /* read prefs */,
3263 NULL /* reply */,
3264 &error);
3265
3266 if (!ret) {
3267 goto fail;
3268 }
3269
3270 /* Create a new data key and a schema using it for encryption. Save the
3271 * schema to the file jsonSchema.json */
3272 ret = create_schema_file (
3273 kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3274
3275 if (!ret) {
3276 goto fail;
3277 }
3278
3279 /* Load the JSON Schema and construct the local schema_map option. */
3280 reader = bson_json_reader_new_from_file ("jsonSchema.json", &error);
3281 if (!reader) {
3282 goto fail;
3283 }
3284
3285 bson_json_reader_read (reader, &schema, &error);
3286
3287 /* Construct the schema map, mapping the namespace of the collection to the
3288 * schema describing encryption. */
3289 schema_map =
3290 BCON_NEW (ENCRYPTED_DB "." ENCRYPTED_COLL, BCON_DOCUMENT (&schema));
3291
3292 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3293 mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3294 keyvault_client);
3295 mongoc_auto_encryption_opts_set_keyvault_namespace (
3296 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3297 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3298 kms_providers);
3299 mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts,
3300 schema_map);
3301
3302 client =
3303 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3304
3305 /* Enable automatic encryption. It will determine that encryption is
3306 * necessary from the schema map instead of relying on the server to provide
3307 * a schema. */
3308 ret = mongoc_client_enable_auto_encryption (
3309 client, auto_encryption_opts, &error);
3310 if (!ret) {
3311 goto fail;
3312 }
3313
3314 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3315
3316 /* Clear old data */
3317 mongoc_collection_drop (coll, NULL);
3318
3319 to_insert = BCON_NEW ("encryptedField", "123456789");
3320 ret = mongoc_collection_insert_one (
3321 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3322 if (!ret) {
3323 goto fail;
3324 }
3325 printf ("decrypted document: ");
3326 if (!print_one_document (coll, &error)) {
3327 goto fail;
3328 }
3329 printf ("\n");
3330
3331 unencrypted_client = mongoc_client_new (
3332 "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3333 unencrypted_coll = mongoc_client_get_collection (
3334 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3335 printf ("encrypted document: ");
3336 if (!print_one_document (unencrypted_coll, &error)) {
3337 goto fail;
3338 }
3339 printf ("\n");
3340
3341 exit_status = EXIT_SUCCESS;
3342 fail:
3343 if (error.code) {
3344 fprintf (stderr, "error: %s\n", error.message);
3345 }
3346
3347 bson_free (local_masterkey);
3348 bson_destroy (kms_providers);
3349 mongoc_collection_destroy (keyvault_coll);
3350 bson_destroy (index_keys);
3351 bson_free (index_name);
3352 bson_destroy (create_index_cmd);
3353 bson_json_reader_destroy (reader);
3354 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3355 mongoc_collection_destroy (coll);
3356 mongoc_client_destroy (client);
3357 bson_destroy (to_insert);
3358 mongoc_collection_destroy (unencrypted_coll);
3359 mongoc_client_destroy (unencrypted_client);
3360 mongoc_client_destroy (keyvault_client);
3361 bson_destroy (&schema);
3362 bson_destroy (schema_map);
3363 mongoc_cleanup ();
3364 return exit_status;
3365 }
3366
3367 Server-Side Field Level Encryption Enforcement
3368 The MongoDB 4.2 server supports using schema validation to enforce
3369 encryption of specific fields in a collection. This schema validation
3370 will prevent an application from inserting unencrypted values for any
3371 fields marked with the "encrypt" JSON schema keyword.
3372
3373 The following example shows how to set up automatic client-side field
3374 level encryption using mongoc_client_encryption_t to create a new
3375 encryption data key and create a collection with the Automatic Encryp‐
3376 tion JSON Schema Syntax:
3377
3378 client-side-encryption-server-schema.c
3379
3380 #include <mongoc/mongoc.h>
3381 #include <stdio.h>
3382 #include <stdlib.h>
3383
3384 #include "client-side-encryption-helpers.h"
3385
3386 /* Helper method to create and return a JSON schema to use for encryption.
3387 The caller will use the returned schema for server-side encryption validation.
3388 */
3389 static bson_t *
3390 create_schema (bson_t *kms_providers,
3391 const char *keyvault_db,
3392 const char *keyvault_coll,
3393 mongoc_client_t *keyvault_client,
3394 bson_error_t *error)
3395 {
3396 mongoc_client_encryption_t *client_encryption = NULL;
3397 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3398 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3399 bson_value_t datakey_id = {0};
3400 char *keyaltnames[] = {"mongoc_encryption_example_2"};
3401 bson_t *schema = NULL;
3402
3403 client_encryption_opts = mongoc_client_encryption_opts_new ();
3404 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3405 kms_providers);
3406 mongoc_client_encryption_opts_set_keyvault_namespace (
3407 client_encryption_opts, keyvault_db, keyvault_coll);
3408 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3409 keyvault_client);
3410
3411 client_encryption =
3412 mongoc_client_encryption_new (client_encryption_opts, error);
3413 if (!client_encryption) {
3414 goto fail;
3415 }
3416
3417 /* Create a new data key and json schema for the encryptedField.
3418 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3419 */
3420 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3421 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3422 datakey_opts, keyaltnames, 1);
3423 if (!mongoc_client_encryption_create_datakey (
3424 client_encryption, "local", datakey_opts, &datakey_id, error)) {
3425 goto fail;
3426 }
3427
3428 /* Create a schema describing that "encryptedField" is a string encrypted
3429 * with the newly created data key using deterministic encryption. */
3430 schema = BCON_NEW ("properties",
3431 "{",
3432 "encryptedField",
3433 "{",
3434 "encrypt",
3435 "{",
3436 "keyId",
3437 "[",
3438 BCON_BIN (datakey_id.value.v_binary.subtype,
3439 datakey_id.value.v_binary.data,
3440 datakey_id.value.v_binary.data_len),
3441 "]",
3442 "bsonType",
3443 "string",
3444 "algorithm",
3445 MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3446 "}",
3447 "}",
3448 "}",
3449 "bsonType",
3450 "object");
3451
3452 fail:
3453 mongoc_client_encryption_destroy (client_encryption);
3454 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3455 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3456 bson_value_destroy (&datakey_id);
3457 return schema;
3458 }
3459
3460 /* This example demonstrates how to use automatic encryption with a server-side
3461 * schema using the enterprise version of MongoDB */
3462 int
3463 main (int argc, char **argv)
3464 {
3465 /* The collection used to store the encryption data keys. */
3466 #define KEYVAULT_DB "encryption"
3467 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3468 /* The collection used to store the encrypted documents in this example. */
3469 #define ENCRYPTED_DB "test"
3470 #define ENCRYPTED_COLL "coll"
3471
3472 int exit_status = EXIT_FAILURE;
3473 bool ret;
3474 uint8_t *local_masterkey = NULL;
3475 uint32_t local_masterkey_len;
3476 bson_t *kms_providers = NULL;
3477 bson_error_t error = {0};
3478 bson_t *index_keys = NULL;
3479 char *index_name = NULL;
3480 bson_t *create_index_cmd = NULL;
3481 bson_json_reader_t *reader = NULL;
3482 bson_t *schema = NULL;
3483
3484 /* The MongoClient used to access the key vault (keyvault_namespace). */
3485 mongoc_client_t *keyvault_client = NULL;
3486 mongoc_collection_t *keyvault_coll = NULL;
3487 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3488 mongoc_client_t *client = NULL;
3489 mongoc_collection_t *coll = NULL;
3490 bson_t *to_insert = NULL;
3491 mongoc_client_t *unencrypted_client = NULL;
3492 mongoc_collection_t *unencrypted_coll = NULL;
3493 bson_t *create_cmd = NULL;
3494 bson_t *create_cmd_opts = NULL;
3495 mongoc_write_concern_t *wc = NULL;
3496
3497 mongoc_init ();
3498
3499 /* Configure the master key. This must be the same master key that was used
3500 * to create
3501 * the encryption key. */
3502 local_masterkey =
3503 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3504 if (!local_masterkey || local_masterkey_len != 96) {
3505 fprintf (stderr,
3506 "Specify LOCAL_MASTERKEY environment variable as a "
3507 "secure random 96 byte hex value.\n");
3508 goto fail;
3509 }
3510
3511 kms_providers = BCON_NEW ("local",
3512 "{",
3513 "key",
3514 BCON_BIN (0, local_masterkey, local_masterkey_len),
3515 "}");
3516
3517 /* Set up the key vault for this example. */
3518 keyvault_client = mongoc_client_new (
3519 "mongodb://localhost/?appname=client-side-encryption-keyvault");
3520 keyvault_coll = mongoc_client_get_collection (
3521 keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3522 mongoc_collection_drop (keyvault_coll, NULL);
3523
3524 /* Create a unique index to ensure that two data keys cannot share the same
3525 * keyAltName. This is recommended practice for the key vault. */
3526 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3527 index_name = mongoc_collection_keys_to_index_string (index_keys);
3528 create_index_cmd = BCON_NEW ("createIndexes",
3529 KEYVAULT_COLL,
3530 "indexes",
3531 "[",
3532 "{",
3533 "key",
3534 BCON_DOCUMENT (index_keys),
3535 "name",
3536 index_name,
3537 "unique",
3538 BCON_BOOL (true),
3539 "partialFilterExpression",
3540 "{",
3541 "keyAltNames",
3542 "{",
3543 "$exists",
3544 BCON_BOOL (true),
3545 "}",
3546 "}",
3547 "}",
3548 "]");
3549 ret = mongoc_client_command_simple (keyvault_client,
3550 KEYVAULT_DB,
3551 create_index_cmd,
3552 NULL /* read prefs */,
3553 NULL /* reply */,
3554 &error);
3555
3556 if (!ret) {
3557 goto fail;
3558 }
3559
3560 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3561 mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3562 keyvault_client);
3563 mongoc_auto_encryption_opts_set_keyvault_namespace (
3564 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3565 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3566 kms_providers);
3567 schema = create_schema (
3568 kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3569
3570 if (!schema) {
3571 goto fail;
3572 }
3573
3574 client =
3575 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3576 ret = mongoc_client_enable_auto_encryption (
3577 client, auto_encryption_opts, &error);
3578 if (!ret) {
3579 goto fail;
3580 }
3581
3582 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3583
3584 /* Clear old data */
3585 mongoc_collection_drop (coll, NULL);
3586
3587 /* Create the collection with the encryption JSON Schema. */
3588 create_cmd = BCON_NEW ("create",
3589 ENCRYPTED_COLL,
3590 "validator",
3591 "{",
3592 "$jsonSchema",
3593 BCON_DOCUMENT (schema),
3594 "}");
3595 wc = mongoc_write_concern_new ();
3596 mongoc_write_concern_set_wmajority (wc, 0);
3597 create_cmd_opts = bson_new ();
3598 mongoc_write_concern_append (wc, create_cmd_opts);
3599 ret = mongoc_client_command_with_opts (client,
3600 ENCRYPTED_DB,
3601 create_cmd,
3602 NULL /* read prefs */,
3603 create_cmd_opts,
3604 NULL /* reply */,
3605 &error);
3606 if (!ret) {
3607 goto fail;
3608 }
3609
3610 to_insert = BCON_NEW ("encryptedField", "123456789");
3611 ret = mongoc_collection_insert_one (
3612 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3613 if (!ret) {
3614 goto fail;
3615 }
3616 printf ("decrypted document: ");
3617 if (!print_one_document (coll, &error)) {
3618 goto fail;
3619 }
3620 printf ("\n");
3621
3622 unencrypted_client = mongoc_client_new (
3623 "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3624 unencrypted_coll = mongoc_client_get_collection (
3625 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3626 printf ("encrypted document: ");
3627 if (!print_one_document (unencrypted_coll, &error)) {
3628 goto fail;
3629 }
3630 printf ("\n");
3631
3632 /* Expect a server-side error if inserting with the unencrypted collection.
3633 */
3634 ret = mongoc_collection_insert_one (
3635 unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3636 if (!ret) {
3637 printf ("insert with unencrypted collection failed: %s\n", error.message);
3638 memset (&error, 0, sizeof (error));
3639 }
3640
3641 exit_status = EXIT_SUCCESS;
3642 fail:
3643 if (error.code) {
3644 fprintf (stderr, "error: %s\n", error.message);
3645 }
3646
3647 bson_free (local_masterkey);
3648 bson_destroy (kms_providers);
3649 mongoc_collection_destroy (keyvault_coll);
3650 bson_destroy (index_keys);
3651 bson_free (index_name);
3652 bson_destroy (create_index_cmd);
3653 bson_json_reader_destroy (reader);
3654 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3655 mongoc_collection_destroy (coll);
3656 mongoc_client_destroy (client);
3657 bson_destroy (to_insert);
3658 mongoc_collection_destroy (unencrypted_coll);
3659 mongoc_client_destroy (unencrypted_client);
3660 mongoc_client_destroy (keyvault_client);
3661 bson_destroy (schema);
3662 bson_destroy (create_cmd);
3663 bson_destroy (create_cmd_opts);
3664 mongoc_write_concern_destroy (wc);
3665
3666 mongoc_cleanup ();
3667 return exit_status;
3668 }
3669
3670 Explicit Encryption
3671 Explicit encryption is a MongoDB community feature and does not use the
3672 mongocryptd process. Explicit encryption is provided by the mon‐
3673 goc_client_encryption_t class, for example:
3674
3675 client-side-encryption-explicit.c
3676
3677 #include <mongoc/mongoc.h>
3678 #include <stdio.h>
3679 #include <stdlib.h>
3680
3681 #include "client-side-encryption-helpers.h"
3682
3683 /* This example demonstrates how to use explicit encryption and decryption using
3684 * the community version of MongoDB */
3685 int
3686 main (int argc, char **argv)
3687 {
3688 /* The collection used to store the encryption data keys. */
3689 #define KEYVAULT_DB "encryption"
3690 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3691 /* The collection used to store the encrypted documents in this example. */
3692 #define ENCRYPTED_DB "test"
3693 #define ENCRYPTED_COLL "coll"
3694
3695 int exit_status = EXIT_FAILURE;
3696 bool ret;
3697 uint8_t *local_masterkey = NULL;
3698 uint32_t local_masterkey_len;
3699 bson_t *kms_providers = NULL;
3700 bson_error_t error = {0};
3701 bson_t *index_keys = NULL;
3702 char *index_name = NULL;
3703 bson_t *create_index_cmd = NULL;
3704 bson_t *schema = NULL;
3705 mongoc_client_t *client = NULL;
3706 mongoc_collection_t *coll = NULL;
3707 mongoc_collection_t *keyvault_coll = NULL;
3708 bson_t *to_insert = NULL;
3709 bson_t *create_cmd = NULL;
3710 bson_t *create_cmd_opts = NULL;
3711 mongoc_write_concern_t *wc = NULL;
3712 mongoc_client_encryption_t *client_encryption = NULL;
3713 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3714 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3715 char *keyaltnames[] = {"mongoc_encryption_example_3"};
3716 bson_value_t datakey_id = {0};
3717 bson_value_t encrypted_field = {0};
3718 bson_value_t to_encrypt = {0};
3719 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3720 bson_value_t decrypted = {0};
3721
3722 mongoc_init ();
3723
3724 /* Configure the master key. This must be the same master key that was used
3725 * to create the encryption key. */
3726 local_masterkey =
3727 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3728 if (!local_masterkey || local_masterkey_len != 96) {
3729 fprintf (stderr,
3730 "Specify LOCAL_MASTERKEY environment variable as a "
3731 "secure random 96 byte hex value.\n");
3732 goto fail;
3733 }
3734
3735 kms_providers = BCON_NEW ("local",
3736 "{",
3737 "key",
3738 BCON_BIN (0, local_masterkey, local_masterkey_len),
3739 "}");
3740
3741 /* The mongoc_client_t used to read/write application data. */
3742 client =
3743 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3744 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3745
3746 /* Clear old data */
3747 mongoc_collection_drop (coll, NULL);
3748
3749 /* Set up the key vault for this example. */
3750 keyvault_coll =
3751 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3752 mongoc_collection_drop (keyvault_coll, NULL);
3753
3754 /* Create a unique index to ensure that two data keys cannot share the same
3755 * keyAltName. This is recommended practice for the key vault. */
3756 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3757 index_name = mongoc_collection_keys_to_index_string (index_keys);
3758 create_index_cmd = BCON_NEW ("createIndexes",
3759 KEYVAULT_COLL,
3760 "indexes",
3761 "[",
3762 "{",
3763 "key",
3764 BCON_DOCUMENT (index_keys),
3765 "name",
3766 index_name,
3767 "unique",
3768 BCON_BOOL (true),
3769 "partialFilterExpression",
3770 "{",
3771 "keyAltNames",
3772 "{",
3773 "$exists",
3774 BCON_BOOL (true),
3775 "}",
3776 "}",
3777 "}",
3778 "]");
3779 ret = mongoc_client_command_simple (client,
3780 KEYVAULT_DB,
3781 create_index_cmd,
3782 NULL /* read prefs */,
3783 NULL /* reply */,
3784 &error);
3785
3786 if (!ret) {
3787 goto fail;
3788 }
3789
3790 client_encryption_opts = mongoc_client_encryption_opts_new ();
3791 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3792 kms_providers);
3793 mongoc_client_encryption_opts_set_keyvault_namespace (
3794 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3795
3796 /* Set a mongoc_client_t to use for reading/writing to the key vault. This
3797 * can be the same mongoc_client_t used by the main application. */
3798 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3799 client);
3800 client_encryption =
3801 mongoc_client_encryption_new (client_encryption_opts, &error);
3802 if (!client_encryption) {
3803 goto fail;
3804 }
3805
3806 /* Create a new data key for the encryptedField.
3807 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3808 */
3809 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3810 mongoc_client_encryption_datakey_opts_set_keyaltnames (
3811 datakey_opts, keyaltnames, 1);
3812 if (!mongoc_client_encryption_create_datakey (
3813 client_encryption, "local", datakey_opts, &datakey_id, &error)) {
3814 goto fail;
3815 }
3816
3817 /* Explicitly encrypt a field */
3818 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
3819 mongoc_client_encryption_encrypt_opts_set_algorithm (
3820 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
3821 mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id);
3822 to_encrypt.value_type = BSON_TYPE_UTF8;
3823 to_encrypt.value.v_utf8.str = "123456789";
3824 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
3825
3826 ret = mongoc_client_encryption_encrypt (
3827 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
3828 if (!ret) {
3829 goto fail;
3830 }
3831
3832 to_insert = bson_new ();
3833 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
3834 ret = mongoc_collection_insert_one (
3835 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3836 if (!ret) {
3837 goto fail;
3838 }
3839
3840 printf ("encrypted document: ");
3841 if (!print_one_document (coll, &error)) {
3842 goto fail;
3843 }
3844 printf ("\n");
3845
3846 /* Explicitly decrypt a field */
3847 ret = mongoc_client_encryption_decrypt (
3848 client_encryption, &encrypted_field, &decrypted, &error);
3849 if (!ret) {
3850 goto fail;
3851 }
3852 printf ("decrypted value: %s\n", decrypted.value.v_utf8.str);
3853
3854 exit_status = EXIT_SUCCESS;
3855 fail:
3856 if (error.code) {
3857 fprintf (stderr, "error: %s\n", error.message);
3858 }
3859
3860 bson_free (local_masterkey);
3861 bson_destroy (kms_providers);
3862 mongoc_collection_destroy (keyvault_coll);
3863 bson_destroy (index_keys);
3864 bson_free (index_name);
3865 bson_destroy (create_index_cmd);
3866 mongoc_collection_destroy (coll);
3867 mongoc_client_destroy (client);
3868 bson_destroy (to_insert);
3869 bson_destroy (schema);
3870 bson_destroy (create_cmd);
3871 bson_destroy (create_cmd_opts);
3872 mongoc_write_concern_destroy (wc);
3873 mongoc_client_encryption_destroy (client_encryption);
3874 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3875 mongoc_client_encryption_opts_destroy (client_encryption_opts);
3876 bson_value_destroy (&encrypted_field);
3877 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
3878 bson_value_destroy (&decrypted);
3879 bson_value_destroy (&datakey_id);
3880
3881 mongoc_cleanup ();
3882 return exit_status;
3883 }
3884
3885 Explicit Encryption with Automatic Decryption
3886 Although automatic encryption requires MongoDB 4.2 enterprise or a Mon‐
3887 goDB 4.2 Atlas cluster, automatic decryption is supported for all
3888 users. To configure automatic decryption without automatic encryption
3889 set bypass_auto_encryption=True in mongoc_auto_encryption_opts_t:
3890
3891 client-side-encryption-auto-decryption.c
3892
3893 #include <mongoc/mongoc.h>
3894 #include <stdio.h>
3895 #include <stdlib.h>
3896
3897 #include "client-side-encryption-helpers.h"
3898
3899 /* This example demonstrates how to set up automatic decryption without
3900 * automatic encryption using the community version of MongoDB */
3901 int
3902 main (int argc, char **argv)
3903 {
3904 /* The collection used to store the encryption data keys. */
3905 #define KEYVAULT_DB "encryption"
3906 #define KEYVAULT_COLL "__libmongocTestKeyVault"
3907 /* The collection used to store the encrypted documents in this example. */
3908 #define ENCRYPTED_DB "test"
3909 #define ENCRYPTED_COLL "coll"
3910
3911 int exit_status = EXIT_FAILURE;
3912 bool ret;
3913 uint8_t *local_masterkey = NULL;
3914 uint32_t local_masterkey_len;
3915 bson_t *kms_providers = NULL;
3916 bson_error_t error = {0};
3917 bson_t *index_keys = NULL;
3918 char *index_name = NULL;
3919 bson_t *create_index_cmd = NULL;
3920 bson_t *schema = NULL;
3921 mongoc_client_t *client = NULL;
3922 mongoc_collection_t *coll = NULL;
3923 mongoc_collection_t *keyvault_coll = NULL;
3924 bson_t *to_insert = NULL;
3925 bson_t *create_cmd = NULL;
3926 bson_t *create_cmd_opts = NULL;
3927 mongoc_write_concern_t *wc = NULL;
3928 mongoc_client_encryption_t *client_encryption = NULL;
3929 mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3930 mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3931 char *keyaltnames[] = {"mongoc_encryption_example_4"};
3932 bson_value_t datakey_id = {0};
3933 bson_value_t encrypted_field = {0};
3934 bson_value_t to_encrypt = {0};
3935 mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3936 bson_value_t decrypted = {0};
3937 mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3938 mongoc_client_t *unencrypted_client = NULL;
3939 mongoc_collection_t *unencrypted_coll = NULL;
3940
3941 mongoc_init ();
3942
3943 /* Configure the master key. This must be the same master key that was used
3944 * to create the encryption key. */
3945 local_masterkey =
3946 hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3947 if (!local_masterkey || local_masterkey_len != 96) {
3948 fprintf (stderr,
3949 "Specify LOCAL_MASTERKEY environment variable as a "
3950 "secure random 96 byte hex value.\n");
3951 goto fail;
3952 }
3953
3954 kms_providers = BCON_NEW ("local",
3955 "{",
3956 "key",
3957 BCON_BIN (0, local_masterkey, local_masterkey_len),
3958 "}");
3959
3960 client =
3961 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3962 auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3963 mongoc_auto_encryption_opts_set_keyvault_namespace (
3964 auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3965 mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3966 kms_providers);
3967
3968 /* Setting bypass_auto_encryption to true disables automatic encryption but
3969 * keeps the automatic decryption behavior. bypass_auto_encryption will also
3970 * disable spawning mongocryptd */
3971 mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts,
3972 true);
3973
3974 /* Once bypass_auto_encryption is set, community users can enable auto
3975 * encryption on the client. This will, in fact, only perform automatic
3976 * decryption. */
3977 ret = mongoc_client_enable_auto_encryption (
3978 client, auto_encryption_opts, &error);
3979 if (!ret) {
3980 goto fail;
3981 }
3982
3983 /* Now that automatic decryption is on, we can test it by inserting a
3984 * document with an explicitly encrypted value into the collection. When we
3985 * look up the document later, it should be automatically decrypted for us.
3986 */
3987 coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3988
3989 /* Clear old data */
3990 mongoc_collection_drop (coll, NULL);
3991
3992 /* Set up the key vault for this example. */
3993 keyvault_coll =
3994 mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3995 mongoc_collection_drop (keyvault_coll, NULL);
3996
3997 /* Create a unique index to ensure that two data keys cannot share the same
3998 * keyAltName. This is recommended practice for the key vault. */
3999 index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
4000 index_name = mongoc_collection_keys_to_index_string (index_keys);
4001 create_index_cmd = BCON_NEW ("createIndexes",
4002 KEYVAULT_COLL,
4003 "indexes",
4004 "[",
4005 "{",
4006 "key",
4007 BCON_DOCUMENT (index_keys),
4008 "name",
4009 index_name,
4010 "unique",
4011 BCON_BOOL (true),
4012 "partialFilterExpression",
4013 "{",
4014 "keyAltNames",
4015 "{",
4016 "$exists",
4017 BCON_BOOL (true),
4018 "}",
4019 "}",
4020 "}",
4021 "]");
4022 ret = mongoc_client_command_simple (client,
4023 KEYVAULT_DB,
4024 create_index_cmd,
4025 NULL /* read prefs */,
4026 NULL /* reply */,
4027 &error);
4028
4029 if (!ret) {
4030 goto fail;
4031 }
4032
4033 client_encryption_opts = mongoc_client_encryption_opts_new ();
4034 mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
4035 kms_providers);
4036 mongoc_client_encryption_opts_set_keyvault_namespace (
4037 client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
4038
4039 /* The key vault client is used for reading to/from the key vault. This can
4040 * be the same mongoc_client_t used by the application. */
4041 mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
4042 client);
4043 client_encryption =
4044 mongoc_client_encryption_new (client_encryption_opts, &error);
4045 if (!client_encryption) {
4046 goto fail;
4047 }
4048
4049 /* Create a new data key for the encryptedField.
4050 * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
4051 */
4052 datakey_opts = mongoc_client_encryption_datakey_opts_new ();
4053 mongoc_client_encryption_datakey_opts_set_keyaltnames (
4054 datakey_opts, keyaltnames, 1);
4055 ret = mongoc_client_encryption_create_datakey (
4056 client_encryption, "local", datakey_opts, &datakey_id, &error);
4057 if (!ret) {
4058 goto fail;
4059 }
4060
4061 /* Explicitly encrypt a field. */
4062 encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
4063 mongoc_client_encryption_encrypt_opts_set_algorithm (
4064 encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
4065 mongoc_client_encryption_encrypt_opts_set_keyaltname (
4066 encrypt_opts, "mongoc_encryption_example_4");
4067 to_encrypt.value_type = BSON_TYPE_UTF8;
4068 to_encrypt.value.v_utf8.str = "123456789";
4069 to_encrypt.value.v_utf8.len = strlen (to_encrypt.value.v_utf8.str);
4070
4071 ret = mongoc_client_encryption_encrypt (
4072 client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
4073 if (!ret) {
4074 goto fail;
4075 }
4076
4077 to_insert = bson_new ();
4078 BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
4079 ret = mongoc_collection_insert_one (
4080 coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
4081 if (!ret) {
4082 goto fail;
4083 }
4084
4085 /* When we retrieve the document, any encrypted fields will get automatically
4086 * decrypted by the driver. */
4087 printf ("decrypted document: ");
4088 if (!print_one_document (coll, &error)) {
4089 goto fail;
4090 }
4091 printf ("\n");
4092
4093 unencrypted_client =
4094 mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
4095 unencrypted_coll = mongoc_client_get_collection (
4096 unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
4097
4098 printf ("encrypted document: ");
4099 if (!print_one_document (unencrypted_coll, &error)) {
4100 goto fail;
4101 }
4102 printf ("\n");
4103
4104 exit_status = EXIT_SUCCESS;
4105 fail:
4106 if (error.code) {
4107 fprintf (stderr, "error: %s\n", error.message);
4108 }
4109
4110 bson_free (local_masterkey);
4111 bson_destroy (kms_providers);
4112 mongoc_collection_destroy (keyvault_coll);
4113 bson_destroy (index_keys);
4114 bson_free (index_name);
4115 bson_destroy (create_index_cmd);
4116 mongoc_collection_destroy (coll);
4117 mongoc_client_destroy (client);
4118 bson_destroy (to_insert);
4119 bson_destroy (schema);
4120 bson_destroy (create_cmd);
4121 bson_destroy (create_cmd_opts);
4122 mongoc_write_concern_destroy (wc);
4123 mongoc_client_encryption_destroy (client_encryption);
4124 mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
4125 mongoc_client_encryption_opts_destroy (client_encryption_opts);
4126 bson_value_destroy (&encrypted_field);
4127 mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
4128 bson_value_destroy (&decrypted);
4129 bson_value_destroy (&datakey_id);
4130 mongoc_collection_destroy (unencrypted_coll);
4131 mongoc_client_destroy (unencrypted_client);
4132 mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
4133
4134 mongoc_cleanup ();
4135 return exit_status;
4136 }
4137
4139 MongoDB, Inc
4140
4142 2017-present, MongoDB, Inc
4143
4144
4145
4146
41471.17.4 Feb 04, 2021 MONGOC_GUIDES(3)