1MONGOC_GUIDES(3)                   libmongoc                  MONGOC_GUIDES(3)
2
3
4

CONFIGURING TLS

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                 ┌───────────────────────┬──────────────────────────┐
100mongoc_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
159AUTO  the  default behavior. Link to the system's native TLS library,
160         or attempt to find OpenSSL.
161
162DARWIN link to Secure Transport, the native TLS library on macOS.
163
164WINDOWS link to Secure Channel, the native TLS library on Windows.
165
166OPENSSL link to OpenSSL (libssl). An optional  install  path  may  be
167         specified with OPENSSL_ROOT.
168
169LIBRESSL link to LibreSSL's libtls. (LibreSSL's compatible libssl may
170         be linked to by setting OPENSSL).
171
172OFF 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

COMMON TASKS

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

ADVANCED CONNECTIONS

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

CONNECTION POOLING

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

DATA COMPRESSION

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

CURSORS

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", &gt);
986             BSON_APPEND_TIMESTAMP (&gt, "$gt", last_time, 0);
987             bson_append_document_end (&query, &gt);
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

BULK WRITE OPERATIONS

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

AGGREGATION FRAMEWORK EXAMPLES

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

DISTINCT AND MAPREDUCE

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

USING LIBMONGOC IN A MICROSOFT VISUAL STUDIO PROJECT

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

MANAGE COLLECTION INDEXES

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

AIDS FOR DEBUGGING

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

IN-USE ENCRYPTION

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
4135mongoc_auto_encryption_opts_set_encrypted_fields_map()  only  applies
4136         to Queryable Encryption.
4137
4138mongoc_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

AUTHOR

4158       MongoDB, Inc
4159
4161       2017-present, MongoDB, Inc
4162
4163
4164
4165
41661.25.1                           Nov 08, 2023                 MONGOC_GUIDES(3)
Impressum