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