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

NAME

6       mongoc_guides - Guides
7

CONFIGURING TLS

9   Configuration with URI options
10       Enable TLS by including tls=true in the URI.
11
12          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
13          mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
14
15          mongoc_client_t *client = mongoc_client_new_from_uri (uri);
16
17       The following URI options may be used to further configure TLS:
18
19          ┌────────────────────┬─────────────────────┬─────────────────────┐
20          │Constant            │ Key                 │ Description         │
21          ├────────────────────┼─────────────────────┼─────────────────────┤
22          │MONGOC_URI_TLS      │ tls                 │ {true|false}, indi‐ │
23          │                    │                     │ cating if TLS  must │
24          │                    │                     │ be used.            │
25          ├────────────────────┼─────────────────────┼─────────────────────┤
26          │MONGOC_URI_TLSCER‐  │ tlscertificatekey‐  │ Path to PEM format‐ │
27          │TIFICATEKEYFILE     │ file                │ ted  Private   Key, │
28          │                    │                     │ with   its   Public │
29          │                    │                     │ Certificate    con‐ │
30          │                    │                     │ catenated   at  the │
31          │                    │                     │ end.                │
32          ├────────────────────┼─────────────────────┼─────────────────────┤
33          │MONGOC_URI_TLSCER‐  │ tlscertificatekey‐  │ The   password,  if │
34          │TIFICATEKEY‐        │ password            │ any, to use to  un‐ │
35          │FILEPASSWORD        │                     │ lock encrypted Pri‐ │
36          │                    │                     │ vate Key.           │
37          ├────────────────────┼─────────────────────┼─────────────────────┤
38          │MON‐                │ tlscafile           │ One,  or  a  bundle │
39          │GOC_URI_TLSCAFILE   │                     │ of, Certificate Au‐ │
40          │                    │                     │ thorities      whom │
41          │                    │                     │ should  be  consid‐ │
42          │                    │                     │ ered to be trusted. │
43          ├────────────────────┼─────────────────────┼─────────────────────┤
44          │MONGOC_URI_TLSAL‐   │ tlsallowinvalidcer‐ │ Accept  and  ignore │
45          │LOWINVALIDCERTIFI‐  │ tificates           │ certificate verifi‐ │
46          │CATES               │                     │ cation errors (e.g. │
47          │                    │                     │ untrusted   issuer, │
48          │                    │                     │ expired, etc.)      │
49          ├────────────────────┼─────────────────────┼─────────────────────┤
50          │MONGOC_URI_TLSAL‐   │ tlsallowinvalid‐    │ Ignore     hostname │
51          │LOWINVALIDHOSTNAMES │ hostnames           │ verification of the │
52          │                    │                     │ certificate   (e.g. │
53          │                    │                     │ Man  In The Middle, │
54          │                    │                     │ using  valid   cer‐ │
55          │                    │                     │ tificate,  but  is‐ │
56          │                    │                     │ sued  for   another │
57          │                    │                     │ hostname)           │
58          └────────────────────┴─────────────────────┴─────────────────────┘
59
60
61
62
63
64
65
66
67          │MONGOC_URI_TLSINSE‐ │ tlsinsecure         │ {true|false}, indi‐ │
68          │CURE                │                     │ cating  if insecure │
69          │                    │                     │ TLS options  should │
70          │                    │                     │ be  used. Currently │
71          │                    │                     │ this  implies  MON‐ │
72          │                    │                     │ GOC_URI_TLSALLOWIN‐ │
73          │                    │                     │ VALIDCERTIFICATES   │
74          │                    │                     │ and  MONGOC_URI_TL‐ │
75          │                    │                     │ SALLOWINVALIDHOST‐  │
76          │                    │                     │ NAMES.              │
77          ├────────────────────┼─────────────────────┼─────────────────────┤
78          │MONGOC_URI_TLSDIS‐  │ tlsdisablecertifi‐  │ {true|false}, indi‐ │
79          │ABLECERTIFICATERE‐  │ caterevocationcheck │ cates if revocation │
80          │VOCATIONCHECK       │                     │ checking   (CRL   / │
81          │                    │                     │ OCSP)   should   be │
82          │                    │                     │ disabled.           │
83          ├────────────────────┼─────────────────────┼─────────────────────┤
84          │MONGOC_URI_TLSDIS‐  │ tlsdisableocspend‐  │ {true|false}, indi‐ │
85          │ABLEOCSPEND‐        │ pointcheck          │ cates if  OCSP  re‐ │
86          │POINTCHECK          │                     │ sponder   endpoints │
87          │                    │                     │ should not  be  re‐ │
88          │                    │                     │ quested   when   an │
89          │                    │                     │ OCSP  response   is │
90          │                    │                     │ not stapled.        │
91          └────────────────────┴─────────────────────┴─────────────────────┘
92
93   Configuration with mongoc_ssl_opt_t
94       Alternatively, the mongoc_ssl_opt_t struct may be used to configure TLS
95       with mongoc_client_set_ssl_opts() or mongoc_client_pool_set_ssl_opts().
96       Most of the configurable options can be set using the Connection String
97       URI.
98
99                 ┌───────────────────────┬──────────────────────────┐
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.
592
593   Connecting to a Replica Set
594       Connecting to a replica set is much like  connecting  to  a  standalone
595       MongoDB  server.  Simply specify the replica set name using the ?repli‐
596       caSet=myreplset URI option.
597
598          #include <bson/bson.h>
599          #include <mongoc/mongoc.h>
600
601          int
602          main (int argc, char *argv[])
603          {
604             mongoc_client_t *client;
605
606             mongoc_init ();
607
608             /* Create our MongoDB Client */
609             client = mongoc_client_new (
610                "mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset");
611
612             /* Do some work */
613             /* TODO */
614
615             /* Clean up */
616             mongoc_client_destroy (client);
617             mongoc_cleanup ();
618
619             return 0;
620          }
621
622       TIP:
623          Multiple hostnames can be specified in the MongoDB connection string
624          URI, with a comma separating hosts in the seed list.
625
626          It  is  recommended to use a seed list of members of the replica set
627          to allow the driver to connect to any node.
628
629   Connecting to a Sharded Cluster
630       To connect to a sharded cluster, specify the mongos  nodes  the  client
631       should  connect  to. The C Driver will automatically detect that it has
632       connected to a mongos sharding server.
633
634       If more than one hostname is specified, a seed list will be created  to
635       attempt failover between the mongos instances.
636
637       WARNING:
638          Specifying  the  replicaSet  parameter  when  connecting to a mongos
639          sharding server is invalid.
640
641          #include <bson/bson.h>
642          #include <mongoc/mongoc.h>
643
644          int
645          main (int argc, char *argv[])
646          {
647             mongoc_client_t *client;
648
649             mongoc_init ();
650
651             /* Create our MongoDB Client */
652             client = mongoc_client_new ("mongodb://myshard01:27017/");
653
654             /* Do something with client ... */
655
656             /* Free the client */
657             mongoc_client_destroy (client);
658
659             mongoc_cleanup ();
660
661             return 0;
662          }
663
664   Connecting to an IPv6 Address
665       The MongoDB C Driver will automatically  resolve  IPv6  addresses  from
666       host  names. However, to specify an IPv6 address directly, wrap the ad‐
667       dress in [].
668
669          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://[::1]:27017");
670
671   Connecting with IPv4 and IPv6
672       If connecting to a hostname that has both IPv4 and  IPv6  DNS  records,
673       the  behavior follows RFC-6555. A connection to the IPv6 address is at‐
674       tempted first. If IPv6 fails, then a connection  is  attempted  to  the
675       IPv4  address.  If  the  connection  attempt  to IPv6 does not complete
676       within 250ms, then IPv4 is tried in parallel. Whichever  succeeds  con‐
677       nection  first  cancels  the other. The successful DNS result is cached
678       for 10 minutes.
679
680       As a consequence, attempts to connect to a  mongod  only  listening  on
681       IPv4  may  be  delayed  if  there are both A (IPv4) and AAAA (IPv6) DNS
682       records associated with the host.
683
684       To avoid a delay, configure hostnames to match the  MongoDB  configura‐
685       tion.  That is, only create an A record if the mongod is only listening
686       on IPv4.
687
688   Connecting to a UNIX Domain Socket
689       On UNIX-like systems, the C Driver can connect directly  to  a  MongoDB
690       server  using  a  UNIX  domain socket. Pass the URL-encoded path to the
691       socket, which must be suffixed with .sock. For example, to connect to a
692       domain socket at /tmp/mongodb-27017.sock:
693
694          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://%2Ftmp%2Fmongodb-27017.sock");
695
696       Include username and password like so:
697
698          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://user:pass@%2Ftmp%2Fmongodb-27017.sock");
699
700   Connecting to a server over TLS
701       These are instructions for configuring TLS/SSL connections.
702
703       To run a server locally (on port 27017, for example):
704
705          $ mongod --port 27017 --tlsMode requireTLS --tlsCertificateKeyFile server.pem --tlsCAFile ca.pem
706
707       Add /?tls=true to the end of a client URI.
708
709          mongoc_client_t *client = NULL;
710          client = mongoc_client_new ("mongodb://localhost:27017/?tls=true");
711
712       MongoDB requires client certificates by default, unless the --tlsAllow‐
713       ConnectionsWithoutCertificates is provided. The C Driver can be config‐
714       ured  to  present a client certificate using the URI option tlsCertifi‐
715       cateKeyFile,  which  may  be  referenced  through  the  constant   MON‐
716       GOC_URI_TLSCERTIFICATEKEYFILE.
717
718          mongoc_client_t *client = NULL;
719          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/?tls=true");
720          mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "client.pem");
721
722          client = mongoc_client_new_from_uri (uri);
723
724       The client certificate provided by tlsCertificateKeyFile must be issued
725       by  one  of  the  server  trusted  Certificate  Authorities  listed  in
726       --tlsCAFile,  or  issued by a CA in the native certificate store on the
727       server when omitted.
728
729       See Configuring TLS for more information on the various TLS related op‐
730       tions.
731
732   Compressing data to and from MongoDB
733       MongoDB  3.4 added Snappy compression support, zlib compression in 3.6,
734       and zstd compression in 4.2.  To enable compression support the  client
735       must be configured with which compressors to use:
736
737          mongoc_client_t *client = NULL;
738          client = mongoc_client_new ("mongodb://localhost:27017/?compressors=snappy,zlib,zstd");
739
740       The  compressors option specifies the priority order of compressors the
741       client wants to use. Messages are compressed if the client  and  server
742       share any compressors in common.
743
744       Note  that the compressor used by the server might not be the same com‐
745       pressor as the client used.  For example, if the client uses  the  con‐
746       nection  string  compressors=zlib,snappy  the client will use zlib com‐
747       pression to send data (if possible), but the server might  still  reply
748       using snappy, depending on how the server was configured.
749
750       The driver must be built with zlib and/or snappy and/or zstd support to
751       enable compression support, any unknown (or not compiled in) compressor
752       value  will be ignored. Note: to build with zstd requires cmake 3.12 or
753       higher.
754
755   Additional Connection Options
756       The full list of connection options can be found  in  the  mongoc_uri_t
757       docs.
758
759       Certain socket/connection related options are not configurable:
760
761             ┌──────────────┬─────────────────────┬─────────────────────┐
762             │Option        │ Description         │ Value               │
763             ├──────────────┼─────────────────────┼─────────────────────┤
764             │SO_KEEPALIVE  │ TCP Keep Alive      │ Enabled             │
765             ├──────────────┼─────────────────────┼─────────────────────┤
766             │TCP_KEEPIDLE  │ How  long a connec‐ │ 120 seconds         │
767             │              │ tion needs  to  re‐ │                     │
768             │              │ main   idle  before │                     │
769             │              │ TCP starts  sending │                     │
770             │              │ keepalive probes    │                     │
771             ├──────────────┼─────────────────────┼─────────────────────┤
772             │TCP_KEEPINTVL │ The time in seconds │ 10 seconds          │
773             │              │ between TCP probes  │                     │
774             ├──────────────┼─────────────────────┼─────────────────────┤
775             │TCP_KEEPCNT   │ How many probes  to │ 9 probes            │
776             │              │ send,  without  ac‐ │                     │
777             │              │ knowledgement,  be‐ │                     │
778             │              │ fore  dropping  the │                     │
779             │              │ connection          │                     │
780             ├──────────────┼─────────────────────┼─────────────────────┤
781             │TCP_NODELAY   │ Send   packets   as │ Enabled (no buffer‐ │
782             │              │ soon as possible or │ ing)                │
783             │              │ buffer small  pack‐ │                     │
784             │              │ ets   (Nagle  algo‐ │                     │
785             │              │ rithm)              │                     │
786             └──────────────┴─────────────────────┴─────────────────────┘
787

CONNECTION POOLING

789       The  MongoDB  C  driver  has  two connection modes: single-threaded and
790       pooled. Single-threaded mode is  optimized  for  embedding  the  driver
791       within  languages  like  PHP. Multi-threaded programs should use pooled
792       mode: this mode minimizes the total connection  count,  and  in  pooled
793       mode  background  threads  monitor  the MongoDB server topology, so the
794       program need not block to scan it.
795
796   Single Mode
797       In single mode, your program creates a mongoc_client_t directly:
798
799          mongoc_client_t *client = mongoc_client_new (
800             "mongodb://hostA,hostB/?replicaSet=my_rs");
801
802       The client connects on demand when your program first  uses  it  for  a
803       MongoDB  operation. Using a non-blocking socket per server, it begins a
804       check on each server concurrently, and uses the  asynchronous  poll  or
805       select  function to receive events from the sockets, until all have re‐
806       sponded or timed out. Put another way, in single-threaded  mode  the  C
807       Driver fans out to begin all checks concurrently, then fans in once all
808       checks have completed or timed out. Once the scan completes, the client
809       executes your program's operation and returns.
810
811       In  single  mode,  the client re-scans the server topology roughly once
812       per minute. If more than a minute has elapsed since the previous  scan,
813       the  next operation on the client will block while the client completes
814       its scan. This interval is configurable  with  heartbeatFrequencyMS  in
815       the connection string. (See mongoc_uri_t.)
816
817       A single client opens one connection per server in your topology: these
818       connections are used both for scanning the topology and performing nor‐
819       mal operations.
820
821   Pooled Mode
822       To activate pooled mode, create a mongoc_client_pool_t:
823
824          mongoc_uri_t *uri = mongoc_uri_new (
825             "mongodb://hostA,hostB/?replicaSet=my_rs");
826
827          mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
828
829       When  your  program  first  calls  mongoc_client_pool_pop(),  the  pool
830       launches monitoring threads in the background. Monitoring threads inde‐
831       pendently  connect to all servers in the connection string. As monitor‐
832       ing threads receive hello responses from the servers, they  update  the
833       shared  view  of the server topology. Additional monitoring threads and
834       connections are created  as  new  servers  are  discovered.  Monitoring
835       threads are terminated when servers are removed from the shared view of
836       the server topology.
837
838       Each thread that executes MongoDB operations must check  out  a  client
839       from the pool:
840
841          mongoc_client_t *client = mongoc_client_pool_pop (pool);
842
843          /* use the client for operations ... */
844
845          mongoc_client_pool_push (pool, client);
846
847       The    mongoc_client_t    object   is   not   thread-safe,   only   the
848       mongoc_client_pool_t is.
849
850       When the driver is in pooled mode, your program's  operations  are  un‐
851       blocked  as  soon as monitoring discovers a usable server. For example,
852       if a thread in your program is waiting to execute an  "insert"  on  the
853       primary,  it  is unblocked as soon as the primary is discovered, rather
854       than waiting for all secondaries to be checked as well.
855
856       The pool opens one connection  per  server  for  monitoring,  and  each
857       client  opens its own connection to each server it uses for application
858       operations. Background monitoring threads re-scan servers independently
859       roughly every 10 seconds. This interval is configurable with heartbeat‐
860       FrequencyMS in the connection string. (See mongoc_uri_t.)
861
862       The connection string can also specify waitQueueTimeoutMS to limit  the
863       time  that  mongoc_client_pool_pop()  will  wait  for a client from the
864       pool.  (See mongoc_uri_t.)  If waitQueueTimeoutMS is specified, then it
865       is necessary to confirm that a client was actually returned:
866
867          mongoc_uri_t *uri = mongoc_uri_new (
868             "mongodb://hostA,hostB/?replicaSet=my_rs&waitQueueTimeoutMS=1000");
869
870          mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
871
872          mongoc_client_t *client = mongoc_client_pool_pop (pool);
873
874          if (client) {
875             /* use the client for operations ... */
876
877             mongoc_client_pool_push (pool, client);
878          } else {
879             /* take appropriate action for a timeout */
880          }
881
882       See  Connection  Pool  Options to configure pool size and behavior, and
883       see mongoc_client_pool_t for an extended example  of  a  multi-threaded
884       program that uses the driver in pooled mode.
885

CURSORS

887   Handling Cursor Failures
888       Cursors  exist on a MongoDB server. However, the mongoc_cursor_t struc‐
889       ture gives the local process a handle to the cursor. It is possible for
890       errors  to  occur on the server while iterating a cursor on the client.
891       Even a network partition may occur. This means that applications should
892       be robust in handling cursor failures.
893
894       While  iterating  cursors,  you should check to see if an error has oc‐
895       curred. See the following example for how to robustly check for errors.
896
897          static void
898          print_all_documents (mongoc_collection_t *collection)
899          {
900             mongoc_cursor_t *cursor;
901             const bson_t *doc;
902             bson_error_t error;
903             bson_t query = BSON_INITIALIZER;
904             char *str;
905
906             cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);
907
908             while (mongoc_cursor_next (cursor, &doc)) {
909                str = bson_as_canonical_extended_json (doc, NULL);
910                printf ("%s\n", str);
911                bson_free (str);
912             }
913
914             if (mongoc_cursor_error (cursor, &error)) {
915                fprintf (stderr, "Failed to iterate all documents: %s\n", error.message);
916             }
917
918             mongoc_cursor_destroy (cursor);
919          }
920
921   Destroying Server-Side Cursors
922       The MongoDB C driver will automatically destroy  a  server-side  cursor
923       when  mongoc_cursor_destroy()  is called. Failure to call this function
924       when done with a cursor will leak memory client side as well as consume
925       extra  memory  server side. If the cursor was configured to never time‐
926       out, it will become a memory leak on the server.
927
928   Tailable Cursors
929       Tailable cursors are cursors that remain open even  after  they've  re‐
930       turned  a final result. This way, if more documents are added to a col‐
931       lection (i.e., to the cursor's result set), then you  can  continue  to
932       call mongoc_cursor_next() to retrieve those additional results.
933
934       Here's  a complete test case that demonstrates the use of tailable cur‐
935       sors.
936
937       NOTE:
938          Tailable cursors are for capped collections only.
939
940       An example to tail the oplog from a replica set.
941
942       mongoc-tail.c
943
944          #include <bson/bson.h>
945          #include <mongoc/mongoc.h>
946          #include <stdio.h>
947          #include <stdlib.h>
948
949          #ifdef _WIN32
950          #define sleep(_n) Sleep ((_n) *1000)
951          #endif
952
953
954          static void
955          print_bson (const bson_t *b)
956          {
957             char *str;
958
959             str = bson_as_canonical_extended_json (b, NULL);
960             fprintf (stdout, "%s\n", str);
961             bson_free (str);
962          }
963
964
965          static mongoc_cursor_t *
966          query_collection (mongoc_collection_t *collection, uint32_t last_time)
967          {
968             mongoc_cursor_t *cursor;
969             bson_t query;
970             bson_t gt;
971             bson_t opts;
972
973             BSON_ASSERT (collection);
974
975             bson_init (&query);
976             BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", &gt);
977             BSON_APPEND_TIMESTAMP (&gt, "$gt", last_time, 0);
978             bson_append_document_end (&query, &gt);
979
980             bson_init (&opts);
981             BSON_APPEND_BOOL (&opts, "tailable", true);
982             BSON_APPEND_BOOL (&opts, "awaitData", true);
983
984             cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL);
985
986             bson_destroy (&query);
987             bson_destroy (&opts);
988
989             return cursor;
990          }
991
992
993          static void
994          tail_collection (mongoc_collection_t *collection)
995          {
996             mongoc_cursor_t *cursor;
997             uint32_t last_time;
998             const bson_t *doc;
999             bson_error_t error;
1000             bson_iter_t iter;
1001
1002             BSON_ASSERT (collection);
1003
1004             last_time = (uint32_t) time (NULL);
1005
1006             while (true) {
1007                cursor = query_collection (collection, last_time);
1008                while (!mongoc_cursor_error (cursor, &error) &&
1009                       mongoc_cursor_more (cursor)) {
1010                   if (mongoc_cursor_next (cursor, &doc)) {
1011                      if (bson_iter_init_find (&iter, doc, "ts") &&
1012                          BSON_ITER_HOLDS_TIMESTAMP (&iter)) {
1013                         bson_iter_timestamp (&iter, &last_time, NULL);
1014                      }
1015                      print_bson (doc);
1016                   }
1017                }
1018                if (mongoc_cursor_error (cursor, &error)) {
1019                   if (error.domain == MONGOC_ERROR_SERVER) {
1020                      fprintf (stderr, "%s\n", error.message);
1021                      exit (1);
1022                   }
1023                }
1024
1025                mongoc_cursor_destroy (cursor);
1026                sleep (1);
1027             }
1028          }
1029
1030
1031          int
1032          main (int argc, char *argv[])
1033          {
1034             mongoc_collection_t *collection;
1035             mongoc_client_t *client;
1036             mongoc_uri_t *uri;
1037             bson_error_t error;
1038
1039             if (argc != 2) {
1040                fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]);
1041                return EXIT_FAILURE;
1042             }
1043
1044             mongoc_init ();
1045
1046             uri = mongoc_uri_new_with_error (argv[1], &error);
1047             if (!uri) {
1048                fprintf (stderr,
1049                         "failed to parse URI: %s\n"
1050                         "error message:       %s\n",
1051                         argv[1],
1052                         error.message);
1053                return EXIT_FAILURE;
1054             }
1055
1056             client = mongoc_client_new_from_uri (uri);
1057             if (!client) {
1058                return EXIT_FAILURE;
1059             }
1060
1061             mongoc_client_set_error_api (client, 2);
1062
1063             collection = mongoc_client_get_collection (client, "local", "oplog.rs");
1064
1065             tail_collection (collection);
1066
1067             mongoc_collection_destroy (collection);
1068             mongoc_uri_destroy (uri);
1069             mongoc_client_destroy (client);
1070
1071             return EXIT_SUCCESS;
1072          }
1073
1074
1075       Let's compile and run this example against a replica set to see updates
1076       as they are made.
1077
1078          $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0)
1079          $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet
1080          {
1081              "h" : -8458503739429355503,
1082              "ns" : "test.test",
1083              "o" : {
1084                  "_id" : {
1085                      "$oid" : "5372ab0a25164be923d10d50"
1086                  }
1087              },
1088              "op" : "i",
1089              "ts" : {
1090                  "$timestamp" : {
1091                      "i" : 1,
1092                      "t" : 1400023818
1093                  }
1094              },
1095              "v" : 2
1096          }
1097
1098       The  line of output is a sample from performing db.test.insert({}) from
1099       the mongo shell on the replica set.
1100
1101       SEE ALSO:
1102          mongoc_cursor_set_max_await_time_ms().
1103
1104

BULK WRITE OPERATIONS

1106       This tutorial explains how to take advantage of MongoDB C  driver  bulk
1107       write operation features. Executing write operations in batches reduces
1108       the number of network round trips, increasing write throughput.
1109
1110   Bulk Insert
1111       First  we  need  to  fetch   a   bulk   operation   handle   from   the
1112       mongoc_collection_t.
1113
1114          mongoc_bulk_operation_t *bulk =
1115             mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1116
1117       We  can now start inserting documents to the bulk operation. These will
1118       be buffered until we execute the operation.
1119
1120       The bulk operation will coalesce insertions as a single batch for  each
1121       consecutive  call  to  mongoc_bulk_operation_insert().  This  creates a
1122       pipelined effect when possible.
1123
1124       To  execute  the  bulk  operation  and  receive  the  result  we   call
1125       mongoc_bulk_operation_execute().
1126
1127       bulk1.c
1128
1129          #include <assert.h>
1130          #include <mongoc/mongoc.h>
1131          #include <stdio.h>
1132
1133          static void
1134          bulk1 (mongoc_collection_t *collection)
1135          {
1136             mongoc_bulk_operation_t *bulk;
1137             bson_error_t error;
1138             bson_t *doc;
1139             bson_t reply;
1140             char *str;
1141             bool ret;
1142             int i;
1143
1144             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1145
1146             for (i = 0; i < 10000; i++) {
1147                doc = BCON_NEW ("i", BCON_INT32 (i));
1148                mongoc_bulk_operation_insert (bulk, doc);
1149                bson_destroy (doc);
1150             }
1151
1152             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1153
1154             str = bson_as_canonical_extended_json (&reply, NULL);
1155             printf ("%s\n", str);
1156             bson_free (str);
1157
1158             if (!ret) {
1159                fprintf (stderr, "Error: %s\n", error.message);
1160             }
1161
1162             bson_destroy (&reply);
1163             mongoc_bulk_operation_destroy (bulk);
1164          }
1165
1166          int
1167          main (void)
1168          {
1169             mongoc_client_t *client;
1170             mongoc_collection_t *collection;
1171             const char *uri_string = "mongodb://localhost/?appname=bulk1-example";
1172             mongoc_uri_t *uri;
1173             bson_error_t error;
1174
1175             mongoc_init ();
1176
1177             uri = mongoc_uri_new_with_error (uri_string, &error);
1178             if (!uri) {
1179                fprintf (stderr,
1180                         "failed to parse URI: %s\n"
1181                         "error message:       %s\n",
1182                         uri_string,
1183                         error.message);
1184                return EXIT_FAILURE;
1185             }
1186
1187             client = mongoc_client_new_from_uri (uri);
1188             if (!client) {
1189                return EXIT_FAILURE;
1190             }
1191
1192             mongoc_client_set_error_api (client, 2);
1193             collection = mongoc_client_get_collection (client, "test", "test");
1194
1195             bulk1 (collection);
1196
1197             mongoc_uri_destroy (uri);
1198             mongoc_collection_destroy (collection);
1199             mongoc_client_destroy (client);
1200
1201             mongoc_cleanup ();
1202
1203             return EXIT_SUCCESS;
1204          }
1205
1206
1207       Example reply document:
1208
1209          {"nInserted"   : 10000,
1210           "nMatched"    : 0,
1211           "nModified"   : 0,
1212           "nRemoved"    : 0,
1213           "nUpserted"   : 0,
1214           "writeErrors" : []
1215           "writeConcernErrors" : [] }
1216
1217   Mixed Bulk Write Operations
1218       MongoDB C driver also supports executing mixed bulk write operations. A
1219       batch of insert, update, and remove operations can be executed together
1220       using the bulk write operations API.
1221
1222   Ordered Bulk Write Operations
1223       Ordered bulk write operations are batched and sent to the server in the
1224       order provided for serial execution. The reply document  describes  the
1225       type and count of operations performed.
1226
1227       bulk2.c
1228
1229          #include <assert.h>
1230          #include <mongoc/mongoc.h>
1231          #include <stdio.h>
1232
1233          static void
1234          bulk2 (mongoc_collection_t *collection)
1235          {
1236             mongoc_bulk_operation_t *bulk;
1237             bson_error_t error;
1238             bson_t *query;
1239             bson_t *doc;
1240             bson_t *opts;
1241             bson_t reply;
1242             char *str;
1243             bool ret;
1244             int i;
1245
1246             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1247
1248             /* Remove everything */
1249             query = bson_new ();
1250             mongoc_bulk_operation_remove (bulk, query);
1251             bson_destroy (query);
1252
1253             /* Add a few documents */
1254             for (i = 1; i < 4; i++) {
1255                doc = BCON_NEW ("_id", BCON_INT32 (i));
1256                mongoc_bulk_operation_insert (bulk, doc);
1257                bson_destroy (doc);
1258             }
1259
1260             /* {_id: 1} => {$set: {foo: "bar"}} */
1261             query = BCON_NEW ("_id", BCON_INT32 (1));
1262             doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}");
1263             mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, NULL, &error);
1264             bson_destroy (query);
1265             bson_destroy (doc);
1266
1267             /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */
1268             opts = BCON_NEW ("upsert", BCON_BOOL (true));
1269             query = BCON_NEW ("_id", BCON_INT32 (4));
1270             doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}");
1271             mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, opts, &error);
1272             bson_destroy (query);
1273             bson_destroy (doc);
1274             bson_destroy (opts);
1275
1276             /* replace {j:1} with {j:2} */
1277             query = BCON_NEW ("j", BCON_INT32 (1));
1278             doc = BCON_NEW ("j", BCON_INT32 (2));
1279             mongoc_bulk_operation_replace_one_with_opts (bulk, query, doc, NULL, &error);
1280             bson_destroy (query);
1281             bson_destroy (doc);
1282
1283             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1284
1285             str = bson_as_canonical_extended_json (&reply, NULL);
1286             printf ("%s\n", str);
1287             bson_free (str);
1288
1289             if (!ret) {
1290                printf ("Error: %s\n", error.message);
1291             }
1292
1293             bson_destroy (&reply);
1294             mongoc_bulk_operation_destroy (bulk);
1295          }
1296
1297          int
1298          main (void)
1299          {
1300             mongoc_client_t *client;
1301             mongoc_collection_t *collection;
1302             const char *uri_string = "mongodb://localhost/?appname=bulk2-example";
1303             mongoc_uri_t *uri;
1304             bson_error_t error;
1305
1306             mongoc_init ();
1307
1308             uri = mongoc_uri_new_with_error (uri_string, &error);
1309             if (!uri) {
1310                fprintf (stderr,
1311                         "failed to parse URI: %s\n"
1312                         "error message:       %s\n",
1313                         uri_string,
1314                         error.message);
1315                return EXIT_FAILURE;
1316             }
1317
1318             client = mongoc_client_new_from_uri (uri);
1319             if (!client) {
1320                return EXIT_FAILURE;
1321             }
1322
1323             mongoc_client_set_error_api (client, 2);
1324             collection = mongoc_client_get_collection (client, "test", "test");
1325
1326             bulk2 (collection);
1327
1328             mongoc_uri_destroy (uri);
1329             mongoc_collection_destroy (collection);
1330             mongoc_client_destroy (client);
1331
1332             mongoc_cleanup ();
1333
1334             return EXIT_SUCCESS;
1335          }
1336
1337
1338       Example reply document:
1339
1340          { "nInserted"   : 3,
1341            "nMatched"    : 2,
1342            "nModified"   : 2,
1343            "nRemoved"    : 10000,
1344            "nUpserted"   : 1,
1345            "upserted"    : [{"index" : 5, "_id" : 4}],
1346            "writeErrors" : []
1347            "writeConcernErrors" : [] }
1348
1349       The  index  field in the upserted array is the 0-based index of the up‐
1350       sert operation; in this example, the sixth  operation  of  the  overall
1351       bulk operation was an upsert, so its index is 5.
1352
1353   Unordered Bulk Write Operations
1354       Unordered  bulk  write operations are batched and sent to the server in
1355       arbitrary order where they may be executed in parallel. Any errors that
1356       occur are reported after all operations are attempted.
1357
1358       In  the  next  example  the  first and third operations fail due to the
1359       unique constraint on _id. Since we are doing  unordered  execution  the
1360       second and fourth operations succeed.
1361
1362       bulk3.c
1363
1364          #include <assert.h>
1365          #include <mongoc/mongoc.h>
1366          #include <stdio.h>
1367
1368          static void
1369          bulk3 (mongoc_collection_t *collection)
1370          {
1371             bson_t opts = BSON_INITIALIZER;
1372             mongoc_bulk_operation_t *bulk;
1373             bson_error_t error;
1374             bson_t *query;
1375             bson_t *doc;
1376             bson_t reply;
1377             char *str;
1378             bool ret;
1379
1380             /* false indicates unordered */
1381             BSON_APPEND_BOOL (&opts, "ordered", false);
1382             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1383             bson_destroy (&opts);
1384
1385             /* Add a document */
1386             doc = BCON_NEW ("_id", BCON_INT32 (1));
1387             mongoc_bulk_operation_insert (bulk, doc);
1388             bson_destroy (doc);
1389
1390             /* remove {_id: 2} */
1391             query = BCON_NEW ("_id", BCON_INT32 (2));
1392             mongoc_bulk_operation_remove_one (bulk, query);
1393             bson_destroy (query);
1394
1395             /* insert {_id: 3} */
1396             doc = BCON_NEW ("_id", BCON_INT32 (3));
1397             mongoc_bulk_operation_insert (bulk, doc);
1398             bson_destroy (doc);
1399
1400             /* replace {_id:4} {'i': 1} */
1401             query = BCON_NEW ("_id", BCON_INT32 (4));
1402             doc = BCON_NEW ("i", BCON_INT32 (1));
1403             mongoc_bulk_operation_replace_one (bulk, query, doc, false);
1404             bson_destroy (query);
1405             bson_destroy (doc);
1406
1407             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1408
1409             str = bson_as_canonical_extended_json (&reply, NULL);
1410             printf ("%s\n", str);
1411             bson_free (str);
1412
1413             if (!ret) {
1414                printf ("Error: %s\n", error.message);
1415             }
1416
1417             bson_destroy (&reply);
1418             mongoc_bulk_operation_destroy (bulk);
1419             bson_destroy (&opts);
1420          }
1421
1422          int
1423          main (void)
1424          {
1425             mongoc_client_t *client;
1426             mongoc_collection_t *collection;
1427             const char *uri_string = "mongodb://localhost/?appname=bulk3-example";
1428             mongoc_uri_t *uri;
1429             bson_error_t error;
1430
1431             mongoc_init ();
1432
1433             uri = mongoc_uri_new_with_error (uri_string, &error);
1434             if (!uri) {
1435                fprintf (stderr,
1436                         "failed to parse URI: %s\n"
1437                         "error message:       %s\n",
1438                         uri_string,
1439                         error.message);
1440                return EXIT_FAILURE;
1441             }
1442
1443             client = mongoc_client_new_from_uri (uri);
1444             if (!client) {
1445                return EXIT_FAILURE;
1446             }
1447
1448             mongoc_client_set_error_api (client, 2);
1449             collection = mongoc_client_get_collection (client, "test", "test");
1450
1451             bulk3 (collection);
1452
1453             mongoc_uri_destroy (uri);
1454             mongoc_collection_destroy (collection);
1455             mongoc_client_destroy (client);
1456
1457             mongoc_cleanup ();
1458
1459             return EXIT_SUCCESS;
1460          }
1461
1462
1463       Example reply document:
1464
1465          { "nInserted"    : 0,
1466            "nMatched"     : 1,
1467            "nModified"    : 1,
1468            "nRemoved"     : 1,
1469            "nUpserted"    : 0,
1470            "writeErrors"  : [
1471              { "index"  : 0,
1472                "code"   : 11000,
1473                "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" },
1474              { "index"  : 2,
1475                "code"   : 11000,
1476                "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ],
1477            "writeConcernErrors" : [] }
1478
1479          Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }
1480
1481       The bson_error_t domain is MONGOC_ERROR_COMMAND and its code is 11000.
1482
1483   Bulk Operation Bypassing Document Validation
1484       This feature is only available when using MongoDB 3.2 and later.
1485
1486       By  default bulk operations are validated against the schema, if any is
1487       defined. In certain cases however it may be  necessary  to  bypass  the
1488       document validation.
1489
1490       bulk5.c
1491
1492          #include <assert.h>
1493          #include <mongoc/mongoc.h>
1494          #include <stdio.h>
1495
1496          static void
1497          bulk5_fail (mongoc_collection_t *collection)
1498          {
1499             mongoc_bulk_operation_t *bulk;
1500             bson_error_t error;
1501             bson_t *doc;
1502             bson_t reply;
1503             char *str;
1504             bool ret;
1505
1506             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1507
1508             /* Two inserts */
1509             doc = BCON_NEW ("_id", BCON_INT32 (31));
1510             mongoc_bulk_operation_insert (bulk, doc);
1511             bson_destroy (doc);
1512
1513             doc = BCON_NEW ("_id", BCON_INT32 (32));
1514             mongoc_bulk_operation_insert (bulk, doc);
1515             bson_destroy (doc);
1516
1517             /* The above documents do not comply to the schema validation rules
1518              * we created previously, so this will result in an error */
1519             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1520
1521             str = bson_as_canonical_extended_json (&reply, NULL);
1522             printf ("%s\n", str);
1523             bson_free (str);
1524
1525             if (!ret) {
1526                printf ("Error: %s\n", error.message);
1527             }
1528
1529             bson_destroy (&reply);
1530             mongoc_bulk_operation_destroy (bulk);
1531          }
1532
1533          static void
1534          bulk5_success (mongoc_collection_t *collection)
1535          {
1536             mongoc_bulk_operation_t *bulk;
1537             bson_error_t error;
1538             bson_t *doc;
1539             bson_t reply;
1540             char *str;
1541             bool ret;
1542
1543             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1544
1545             /* Allow this document to bypass document validation.
1546              * NOTE: When authentication is enabled, the authenticated user must have
1547              * either the "dbadmin" or "restore" roles to bypass document validation */
1548             mongoc_bulk_operation_set_bypass_document_validation (bulk, true);
1549
1550             /* Two inserts */
1551             doc = BCON_NEW ("_id", BCON_INT32 (31));
1552             mongoc_bulk_operation_insert (bulk, doc);
1553             bson_destroy (doc);
1554
1555             doc = BCON_NEW ("_id", BCON_INT32 (32));
1556             mongoc_bulk_operation_insert (bulk, doc);
1557             bson_destroy (doc);
1558
1559             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1560
1561             str = bson_as_canonical_extended_json (&reply, NULL);
1562             printf ("%s\n", str);
1563             bson_free (str);
1564
1565             if (!ret) {
1566                printf ("Error: %s\n", error.message);
1567             }
1568
1569             bson_destroy (&reply);
1570             mongoc_bulk_operation_destroy (bulk);
1571          }
1572
1573          int
1574          main (void)
1575          {
1576             bson_t *options;
1577             bson_error_t error;
1578             mongoc_client_t *client;
1579             mongoc_collection_t *collection;
1580             mongoc_database_t *database;
1581             const char *uri_string = "mongodb://localhost/?appname=bulk5-example";
1582             mongoc_uri_t *uri;
1583
1584             mongoc_init ();
1585
1586             uri = mongoc_uri_new_with_error (uri_string, &error);
1587             if (!uri) {
1588                fprintf (stderr,
1589                         "failed to parse URI: %s\n"
1590                         "error message:       %s\n",
1591                         uri_string,
1592                         error.message);
1593                return EXIT_FAILURE;
1594             }
1595
1596             client = mongoc_client_new_from_uri (uri);
1597             if (!client) {
1598                return EXIT_FAILURE;
1599             }
1600
1601             mongoc_client_set_error_api (client, 2);
1602             database = mongoc_client_get_database (client, "testasdf");
1603
1604             /* Create schema validator */
1605             options = BCON_NEW (
1606                "validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}");
1607             collection =
1608                mongoc_database_create_collection (database, "collname", options, &error);
1609
1610             if (collection) {
1611                bulk5_fail (collection);
1612                bulk5_success (collection);
1613                mongoc_collection_destroy (collection);
1614             } else {
1615                fprintf (stderr, "Couldn't create collection: '%s'\n", error.message);
1616             }
1617
1618             bson_free (options);
1619             mongoc_uri_destroy (uri);
1620             mongoc_database_destroy (database);
1621             mongoc_client_destroy (client);
1622
1623             mongoc_cleanup ();
1624
1625             return EXIT_SUCCESS;
1626          }
1627
1628
1629       Running the above example will result in:
1630
1631          { "nInserted" : 0,
1632            "nMatched" : 0,
1633            "nModified" : 0,
1634            "nRemoved" : 0,
1635            "nUpserted" : 0,
1636            "writeErrors" : [
1637              { "index" : 0,
1638                "code" : 121,
1639                "errmsg" : "Document failed validation" } ] }
1640
1641          Error: Document failed validation
1642
1643          { "nInserted" : 2,
1644            "nMatched" : 0,
1645            "nModified" : 0,
1646            "nRemoved" : 0,
1647            "nUpserted" : 0,
1648            "writeErrors" : [] }
1649
1650       The bson_error_t domain is MONGOC_ERROR_COMMAND.
1651
1652   Bulk Operation Write Concerns
1653       By  default  bulk operations are executed with the write_concern of the
1654       collection they are executed against. A custom  write  concern  can  be
1655       passed   to   the   mongoc_collection_create_bulk_operation_with_opts()
1656       method. Write concern errors (e.g. wtimeout) will be reported after all
1657       operations are attempted, regardless of execution order.
1658
1659       bulk4.c
1660
1661          #include <assert.h>
1662          #include <mongoc/mongoc.h>
1663          #include <stdio.h>
1664
1665          static void
1666          bulk4 (mongoc_collection_t *collection)
1667          {
1668             bson_t opts = BSON_INITIALIZER;
1669             mongoc_write_concern_t *wc;
1670             mongoc_bulk_operation_t *bulk;
1671             bson_error_t error;
1672             bson_t *doc;
1673             bson_t reply;
1674             char *str;
1675             bool ret;
1676
1677             wc = mongoc_write_concern_new ();
1678             mongoc_write_concern_set_w (wc, 4);
1679             mongoc_write_concern_set_wtimeout_int64 (wc, 100); /* milliseconds */
1680             mongoc_write_concern_append (wc, &opts);
1681
1682             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1683
1684             /* Two inserts */
1685             doc = BCON_NEW ("_id", BCON_INT32 (10));
1686             mongoc_bulk_operation_insert (bulk, doc);
1687             bson_destroy (doc);
1688
1689             doc = BCON_NEW ("_id", BCON_INT32 (11));
1690             mongoc_bulk_operation_insert (bulk, doc);
1691             bson_destroy (doc);
1692
1693             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1694
1695             str = bson_as_canonical_extended_json (&reply, NULL);
1696             printf ("%s\n", str);
1697             bson_free (str);
1698
1699             if (!ret) {
1700                printf ("Error: %s\n", error.message);
1701             }
1702
1703             bson_destroy (&reply);
1704             mongoc_bulk_operation_destroy (bulk);
1705             mongoc_write_concern_destroy (wc);
1706             bson_destroy (&opts);
1707          }
1708
1709          int
1710          main (void)
1711          {
1712             mongoc_client_t *client;
1713             mongoc_collection_t *collection;
1714             const char *uri_string = "mongodb://localhost/?appname=bulk4-example";
1715             mongoc_uri_t *uri;
1716             bson_error_t error;
1717
1718             mongoc_init ();
1719
1720             uri = mongoc_uri_new_with_error (uri_string, &error);
1721             if (!uri) {
1722                fprintf (stderr,
1723                         "failed to parse URI: %s\n"
1724                         "error message:       %s\n",
1725                         uri_string,
1726                         error.message);
1727                return EXIT_FAILURE;
1728             }
1729
1730             client = mongoc_client_new_from_uri (uri);
1731             if (!client) {
1732                return EXIT_FAILURE;
1733             }
1734
1735             mongoc_client_set_error_api (client, 2);
1736             collection = mongoc_client_get_collection (client, "test", "test");
1737
1738             bulk4 (collection);
1739
1740             mongoc_uri_destroy (uri);
1741             mongoc_collection_destroy (collection);
1742             mongoc_client_destroy (client);
1743
1744             mongoc_cleanup ();
1745
1746             return EXIT_SUCCESS;
1747          }
1748
1749
1750       Example reply document and error message:
1751
1752          { "nInserted"    : 2,
1753            "nMatched"     : 0,
1754            "nModified"    : 0,
1755            "nRemoved"     : 0,
1756            "nUpserted"    : 0,
1757            "writeErrors"  : [],
1758            "writeConcernErrors" : [
1759              { "code"   : 64,
1760                "errmsg" : "waiting for replication timed out" }
1761          ] }
1762
1763          Error: waiting for replication timed out
1764
1765       The  bson_error_t  domain  is  MONGOC_ERROR_WRITE_CONCERN  if there are
1766       write concern errors and no write errors. Write errors indicate  failed
1767       operations,  so  they  take precedence over write concern errors, which
1768       mean merely that the write concern is not satisfied yet.
1769
1770   Setting Collation Order
1771       This feature is only available when using MongoDB 3.4 and later.
1772
1773       bulk-collation.c
1774
1775          #include <mongoc/mongoc.h>
1776          #include <stdio.h>
1777
1778          static void
1779          bulk_collation (mongoc_collection_t *collection)
1780          {
1781             mongoc_bulk_operation_t *bulk;
1782             bson_t *opts;
1783             bson_t *doc;
1784             bson_t *selector;
1785             bson_t *update;
1786             bson_error_t error;
1787             bson_t reply;
1788             char *str;
1789             uint32_t ret;
1790
1791             /* insert {_id: "one"} and {_id: "One"} */
1792             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
1793             doc = BCON_NEW ("_id", BCON_UTF8 ("one"));
1794             mongoc_bulk_operation_insert (bulk, doc);
1795             bson_destroy (doc);
1796
1797             doc = BCON_NEW ("_id", BCON_UTF8 ("One"));
1798             mongoc_bulk_operation_insert (bulk, doc);
1799             bson_destroy (doc);
1800
1801             /* "One" normally sorts before "one"; make "one" come first */
1802             opts = BCON_NEW ("collation",
1803                              "{",
1804                              "locale",
1805                              BCON_UTF8 ("en_US"),
1806                              "caseFirst",
1807                              BCON_UTF8 ("lower"),
1808                              "}");
1809
1810             /* set x=1 on the document with _id "One", which now sorts after "one" */
1811             update = BCON_NEW ("$set", "{", "x", BCON_INT64 (1), "}");
1812             selector = BCON_NEW ("_id", "{", "$gt", BCON_UTF8 ("one"), "}");
1813             mongoc_bulk_operation_update_one_with_opts (
1814                bulk, selector, update, opts, &error);
1815
1816             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1817
1818             str = bson_as_canonical_extended_json (&reply, NULL);
1819             printf ("%s\n", str);
1820             bson_free (str);
1821
1822             if (!ret) {
1823                printf ("Error: %s\n", error.message);
1824             }
1825
1826             bson_destroy (&reply);
1827             bson_destroy (update);
1828             bson_destroy (selector);
1829             bson_destroy (opts);
1830             mongoc_bulk_operation_destroy (bulk);
1831          }
1832
1833          int
1834          main (void)
1835          {
1836             mongoc_client_t *client;
1837             mongoc_collection_t *collection;
1838             const char *uri_string = "mongodb://localhost/?appname=bulk-collation";
1839             mongoc_uri_t *uri;
1840             bson_error_t error;
1841
1842             mongoc_init ();
1843
1844             uri = mongoc_uri_new_with_error (uri_string, &error);
1845             if (!uri) {
1846                fprintf (stderr,
1847                         "failed to parse URI: %s\n"
1848                         "error message:       %s\n",
1849                         uri_string,
1850                         error.message);
1851                return EXIT_FAILURE;
1852             }
1853
1854             client = mongoc_client_new_from_uri (uri);
1855             if (!client) {
1856                return EXIT_FAILURE;
1857             }
1858
1859             mongoc_client_set_error_api (client, 2);
1860             collection = mongoc_client_get_collection (client, "db", "collection");
1861             bulk_collation (collection);
1862
1863             mongoc_uri_destroy (uri);
1864             mongoc_collection_destroy (collection);
1865             mongoc_client_destroy (client);
1866
1867             mongoc_cleanup ();
1868
1869             return EXIT_SUCCESS;
1870          }
1871
1872
1873       Running the above example will result in:
1874
1875          { "nInserted" : 2,
1876             "nMatched" : 1,
1877             "nModified" : 1,
1878             "nRemoved" : 0,
1879             "nUpserted" : 0,
1880             "writeErrors" : [  ]
1881          }
1882
1883   Unacknowledged Bulk Writes
1884       Set "w" to zero for an unacknowledged write.  The  driver  sends  unac‐
1885       knowledged  writes  using  the legacy opcodes OP_INSERT, OP_UPDATE, and
1886       OP_DELETE.
1887
1888       bulk6.c
1889
1890          #include <mongoc/mongoc.h>
1891          #include <stdio.h>
1892
1893          static void
1894          bulk6 (mongoc_collection_t *collection)
1895          {
1896             bson_t opts = BSON_INITIALIZER;
1897             mongoc_write_concern_t *wc;
1898             mongoc_bulk_operation_t *bulk;
1899             bson_error_t error;
1900             bson_t *doc;
1901             bson_t *selector;
1902             bson_t reply;
1903             char *str;
1904             bool ret;
1905
1906             wc = mongoc_write_concern_new ();
1907             mongoc_write_concern_set_w (wc, 0);
1908             mongoc_write_concern_append (wc, &opts);
1909
1910             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
1911
1912             doc = BCON_NEW ("_id", BCON_INT32 (10));
1913             mongoc_bulk_operation_insert (bulk, doc);
1914             bson_destroy (doc);
1915
1916             selector = BCON_NEW ("_id", BCON_INT32 (11));
1917             mongoc_bulk_operation_remove_one (bulk, selector);
1918             bson_destroy (selector);
1919
1920             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
1921
1922             str = bson_as_canonical_extended_json (&reply, NULL);
1923             printf ("%s\n", str);
1924             bson_free (str);
1925
1926             if (!ret) {
1927                printf ("Error: %s\n", error.message);
1928             }
1929
1930             bson_destroy (&reply);
1931             mongoc_bulk_operation_destroy (bulk);
1932             mongoc_write_concern_destroy (wc);
1933             bson_destroy (&opts);
1934          }
1935
1936          int
1937          main (void)
1938          {
1939             mongoc_client_t *client;
1940             mongoc_collection_t *collection;
1941             const char *uri_string = "mongodb://localhost/?appname=bulk6-example";
1942             mongoc_uri_t *uri;
1943             bson_error_t error;
1944
1945             mongoc_init ();
1946
1947             uri = mongoc_uri_new_with_error (uri_string, &error);
1948             if (!uri) {
1949                fprintf (stderr,
1950                         "failed to parse URI: %s\n"
1951                         "error message:       %s\n",
1952                         uri_string,
1953                         error.message);
1954                return EXIT_FAILURE;
1955             }
1956
1957             client = mongoc_client_new_from_uri (uri);
1958             if (!client) {
1959                return EXIT_FAILURE;
1960             }
1961
1962             mongoc_client_set_error_api (client, 2);
1963             collection = mongoc_client_get_collection (client, "test", "test");
1964
1965             bulk6 (collection);
1966
1967             mongoc_uri_destroy (uri);
1968             mongoc_collection_destroy (collection);
1969             mongoc_client_destroy (client);
1970
1971             mongoc_cleanup ();
1972
1973             return EXIT_SUCCESS;
1974          }
1975
1976
1977       The reply document is empty:
1978
1979          { }
1980
1981   Further Reading
1982       See the Driver Bulk API Spec, which describes bulk write operations for
1983       all MongoDB drivers.
1984

AGGREGATION FRAMEWORK EXAMPLES

1986       This  document provides a number of practical examples that display the
1987       capabilities of the aggregation framework.
1988
1989       The Aggregations using the Zip Codes Data Set examples uses a  publicly
1990       available  data  set  of  all  zipcodes  and  populations in the United
1991       States. These data are available at: zips.json.
1992
1993   Requirements
1994       Let's check if everything is installed.
1995
1996       Use the following command to load zips.json data set  into  mongod  in‐
1997       stance:
1998
1999          $ mongoimport --drop -d test -c zipcodes zips.json
2000
2001       Let's use the MongoDB shell to verify that everything was imported suc‐
2002       cessfully.
2003
2004          $ mongo test
2005          connecting to: test
2006          > db.zipcodes.count()
2007          29467
2008          > db.zipcodes.findOne()
2009          {
2010                "_id" : "35004",
2011                "city" : "ACMAR",
2012                "loc" : [
2013                        -86.51557,
2014                        33.584132
2015                ],
2016                "pop" : 6055,
2017                "state" : "AL"
2018          }
2019
2020   Aggregations using the Zip Codes Data Set
2021       Each document in this collection has the following form:
2022
2023          {
2024            "_id" : "35004",
2025            "city" : "Acmar",
2026            "state" : "AL",
2027            "pop" : 6055,
2028            "loc" : [-86.51557, 33.584132]
2029          }
2030
2031       In these documents:
2032
2033       • The _id field holds the zipcode as a string.
2034
2035       • The city field holds the city name.
2036
2037       • The state field holds the two letter state abbreviation.
2038
2039       • The pop field holds the population.
2040
2041       • The loc field holds the location as a [latitude, longitude] array.
2042
2043   States with Populations Over 10 Million
2044       To get all states with a population greater than 10  million,  use  the
2045       following aggregation pipeline:
2046
2047       aggregation1.c
2048
2049          #include <mongoc/mongoc.h>
2050          #include <stdio.h>
2051
2052          static void
2053          print_pipeline (mongoc_collection_t *collection)
2054          {
2055             mongoc_cursor_t *cursor;
2056             bson_error_t error;
2057             const bson_t *doc;
2058             bson_t *pipeline;
2059             char *str;
2060
2061             pipeline = BCON_NEW ("pipeline",
2062                                  "[",
2063                                  "{",
2064                                  "$group",
2065                                  "{",
2066                                  "_id",
2067                                  "$state",
2068                                  "total_pop",
2069                                  "{",
2070                                  "$sum",
2071                                  "$pop",
2072                                  "}",
2073                                  "}",
2074                                  "}",
2075                                  "{",
2076                                  "$match",
2077                                  "{",
2078                                  "total_pop",
2079                                  "{",
2080                                  "$gte",
2081                                  BCON_INT32 (10000000),
2082                                  "}",
2083                                  "}",
2084                                  "}",
2085                                  "]");
2086
2087             cursor = mongoc_collection_aggregate (
2088                collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL);
2089
2090             while (mongoc_cursor_next (cursor, &doc)) {
2091                str = bson_as_canonical_extended_json (doc, NULL);
2092                printf ("%s\n", str);
2093                bson_free (str);
2094             }
2095
2096             if (mongoc_cursor_error (cursor, &error)) {
2097                fprintf (stderr, "Cursor Failure: %s\n", error.message);
2098             }
2099
2100             mongoc_cursor_destroy (cursor);
2101             bson_destroy (pipeline);
2102          }
2103
2104          int
2105          main (void)
2106          {
2107             mongoc_client_t *client;
2108             mongoc_collection_t *collection;
2109             const char *uri_string =
2110                "mongodb://localhost:27017/?appname=aggregation-example";
2111             mongoc_uri_t *uri;
2112             bson_error_t error;
2113
2114             mongoc_init ();
2115
2116             uri = mongoc_uri_new_with_error (uri_string, &error);
2117             if (!uri) {
2118                fprintf (stderr,
2119                         "failed to parse URI: %s\n"
2120                         "error message:       %s\n",
2121                         uri_string,
2122                         error.message);
2123                return EXIT_FAILURE;
2124             }
2125
2126             client = mongoc_client_new_from_uri (uri);
2127             if (!client) {
2128                return EXIT_FAILURE;
2129             }
2130
2131             mongoc_client_set_error_api (client, 2);
2132             collection = mongoc_client_get_collection (client, "test", "zipcodes");
2133
2134             print_pipeline (collection);
2135
2136             mongoc_uri_destroy (uri);
2137             mongoc_collection_destroy (collection);
2138             mongoc_client_destroy (client);
2139
2140             mongoc_cleanup ();
2141
2142             return EXIT_SUCCESS;
2143          }
2144
2145
2146       You should see a result like the following:
2147
2148          { "_id" : "PA", "total_pop" : 11881643 }
2149          { "_id" : "OH", "total_pop" : 10847115 }
2150          { "_id" : "NY", "total_pop" : 17990455 }
2151          { "_id" : "FL", "total_pop" : 12937284 }
2152          { "_id" : "TX", "total_pop" : 16986510 }
2153          { "_id" : "IL", "total_pop" : 11430472 }
2154          { "_id" : "CA", "total_pop" : 29760021 }
2155
2156       The  above  aggregation  pipeline is build from two pipeline operators:
2157       $group and $match.
2158
2159       The $group pipeline operator requires _id field where we specify group‐
2160       ing;  remaining fields specify how to generate composite value and must
2161       use one of the group aggregation functions: $addToSet,  $first,  $last,
2162       $max,  $min,  $avg, $push, $sum. The $match pipeline operator syntax is
2163       the same as the read operation query syntax.
2164
2165       The $group process reads all documents and for each state it creates  a
2166       separate document, for example:
2167
2168          { "_id" : "WA", "total_pop" : 4866692 }
2169
2170       The  total_pop field uses the $sum aggregation function to sum the val‐
2171       ues of all pop fields in the source documents.
2172
2173       Documents created by $group are piped to the $match pipeline  operator.
2174       It returns the documents with the value of total_pop field greater than
2175       or equal to 10 million.
2176
2177   Average City Population by State
2178       To get the first three states with the greatest average population  per
2179       city, use the following aggregation:
2180
2181          pipeline = BCON_NEW ("pipeline", "[",
2182             "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}",
2183             "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}",
2184             "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}",
2185             "{", "$limit", BCON_INT32 (3) "}",
2186          "]");
2187
2188       This aggregate pipeline produces:
2189
2190          { "_id" : "DC", "avg_city_pop" : 303450.0 }
2191          { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2192          { "_id" : "CA", "avg_city_pop" : 27735.341099720412 }
2193
2194       The  above aggregation pipeline is build from three pipeline operators:
2195       $group, $sort and $limit.
2196
2197       The first $group operator creates the following documents:
2198
2199          { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 }
2200
2201       Note, that the $group operator can't use nested  documents  except  the
2202       _id field.
2203
2204       The  second  $group  uses these documents to create the following docu‐
2205       ments:
2206
2207          { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
2208
2209       These documents are sorted by the avg_city_pop field in descending  or‐
2210       der.  Finally,  the  $limit pipeline operator returns the first 3 docu‐
2211       ments from the sorted set.
2212

DISTINCT AND MAPREDUCE

2214       This document provides some practical, simple, examples to  demonstrate
2215       the distinct and mapReduce commands.
2216
2217   Setup
2218       First we'll write some code to insert sample data:
2219
2220       doc-common-insert.c
2221
2222          /* Don't try to compile this file on its own. It's meant to be #included
2223             by example code */
2224
2225          /* Insert some sample data */
2226          bool
2227          insert_data (mongoc_collection_t *collection)
2228          {
2229             mongoc_bulk_operation_t *bulk;
2230             enum N { ndocs = 4 };
2231             bson_t *docs[ndocs];
2232             bson_error_t error;
2233             int i = 0;
2234             bool ret;
2235
2236             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
2237
2238             docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
2239             docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
2240             docs[2] = BCON_NEW (
2241                "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
2242             docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
2243
2244             for (i = 0; i < ndocs; i++) {
2245                mongoc_bulk_operation_insert (bulk, docs[i]);
2246                bson_destroy (docs[i]);
2247                docs[i] = NULL;
2248             }
2249
2250             ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
2251
2252             if (!ret) {
2253                fprintf (stderr, "Error inserting data: %s\n", error.message);
2254             }
2255
2256             mongoc_bulk_operation_destroy (bulk);
2257             return ret;
2258          }
2259
2260          /* A helper which we'll use a lot later on */
2261          void
2262          print_res (const bson_t *reply)
2263          {
2264             char *str;
2265             BSON_ASSERT (reply);
2266             str = bson_as_canonical_extended_json (reply, NULL);
2267             printf ("%s\n", str);
2268             bson_free (str);
2269          }
2270
2271
2272   "distinct" command
2273       This is how to use the distinct command to get the distinct values of x
2274       which are greater than 1:
2275
2276       distinct.c
2277
2278          bool
2279          distinct (mongoc_database_t *database)
2280          {
2281             bson_t *command;
2282             bson_t reply;
2283             bson_error_t error;
2284             bool res;
2285             bson_iter_t iter;
2286             bson_iter_t array_iter;
2287             double val;
2288
2289             command = BCON_NEW ("distinct",
2290                                 BCON_UTF8 (COLLECTION_NAME),
2291                                 "key",
2292                                 BCON_UTF8 ("x"),
2293                                 "query",
2294                                 "{",
2295                                 "x",
2296                                 "{",
2297                                 "$gt",
2298                                 BCON_DOUBLE (1.0),
2299                                 "}",
2300                                 "}");
2301             res =
2302                mongoc_database_command_simple (database, command, NULL, &reply, &error);
2303             if (!res) {
2304                fprintf (stderr, "Error with distinct: %s\n", error.message);
2305                goto cleanup;
2306             }
2307
2308             /* Do something with reply (in this case iterate through the values) */
2309             if (!(bson_iter_init_find (&iter, &reply, "values") &&
2310                   BSON_ITER_HOLDS_ARRAY (&iter) &&
2311                   bson_iter_recurse (&iter, &array_iter))) {
2312                fprintf (stderr, "Couldn't extract \"values\" field from response\n");
2313                goto cleanup;
2314             }
2315
2316             while (bson_iter_next (&array_iter)) {
2317                if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) {
2318                   val = bson_iter_double (&array_iter);
2319                   printf ("Next double: %f\n", val);
2320                }
2321             }
2322
2323          cleanup:
2324             /* cleanup */
2325             bson_destroy (command);
2326             bson_destroy (&reply);
2327             return res;
2328          }
2329
2330
2331   "mapReduce" - basic example
2332       A simple example using the map reduce framework. It simply adds up  the
2333       number of occurrences of each "tag".
2334
2335       First define the map and reduce functions:
2336
2337       constants.c
2338
2339          const char *const COLLECTION_NAME = "things";
2340
2341          /* Our map function just emits a single (key, 1) pair for each tag
2342             in the array: */
2343          const char *const MAPPER = "function () {"
2344                                     "this.tags.forEach(function(z) {"
2345                                     "emit(z, 1);"
2346                                     "});"
2347                                     "}";
2348
2349          /* The reduce function sums over all of the emitted values for a
2350             given key: */
2351          const char *const REDUCER = "function (key, values) {"
2352                                      "var total = 0;"
2353                                      "for (var i = 0; i < values.length; i++) {"
2354                                      "total += values[i];"
2355                                      "}"
2356                                      "return total;"
2357                                      "}";
2358          /* Note We can't just return values.length as the reduce function
2359             might be called iteratively on the results of other reduce
2360             steps. */
2361
2362
2363       Run  the  mapReduce  command.  Use  the  generic  command helpers (e.g.
2364       mongoc_database_command_simple()).  Do not  the  read  command  helpers
2365       (e.g.  mongoc_database_read_command_with_opts())  because they are con‐
2366       sidered retryable read operations.  If  retryable  reads  are  enabled,
2367       those  operations will retry once on a retryable error, giving undesir‐
2368       able behavior for mapReduce.
2369
2370       map-reduce-basic.c
2371
2372          bool
2373          map_reduce_basic (mongoc_database_t *database)
2374          {
2375             bson_t reply;
2376             bson_t *command;
2377             bool res;
2378             bson_error_t error;
2379             mongoc_cursor_t *cursor;
2380             const bson_t *doc;
2381
2382             bool query_done = false;
2383
2384             const char *out_collection_name = "outCollection";
2385             mongoc_collection_t *out_collection;
2386
2387             /* Empty find query */
2388             bson_t find_query = BSON_INITIALIZER;
2389
2390             /* Construct the mapReduce command */
2391
2392             /* Other arguments can also be specified here, like "query" or
2393                "limit" and so on */
2394             command = BCON_NEW ("mapReduce",
2395                                 BCON_UTF8 (COLLECTION_NAME),
2396                                 "map",
2397                                 BCON_CODE (MAPPER),
2398                                 "reduce",
2399                                 BCON_CODE (REDUCER),
2400                                 "out",
2401                                 BCON_UTF8 (out_collection_name));
2402             res =
2403                mongoc_database_command_simple (database, command, NULL, &reply, &error);
2404
2405             if (!res) {
2406                fprintf (stderr, "MapReduce failed: %s\n", error.message);
2407                goto cleanup;
2408             }
2409
2410             /* Do something with the reply (it doesn't contain the mapReduce results) */
2411             print_res (&reply);
2412
2413             /* Now we'll query outCollection to see what the results are */
2414             out_collection =
2415                mongoc_database_get_collection (database, out_collection_name);
2416             cursor = mongoc_collection_find_with_opts (
2417                out_collection, &find_query, NULL, NULL);
2418             query_done = true;
2419
2420             /* Do something with the results */
2421             while (mongoc_cursor_next (cursor, &doc)) {
2422                print_res (doc);
2423             }
2424
2425             if (mongoc_cursor_error (cursor, &error)) {
2426                fprintf (stderr, "ERROR: %s\n", error.message);
2427                res = false;
2428                goto cleanup;
2429             }
2430
2431          cleanup:
2432             /* cleanup */
2433             if (query_done) {
2434                mongoc_cursor_destroy (cursor);
2435                mongoc_collection_destroy (out_collection);
2436             }
2437
2438             bson_destroy (&reply);
2439             bson_destroy (command);
2440
2441             return res;
2442          }
2443
2444
2445   "mapReduce" - more complicated example
2446       You must have replica set running for this.
2447
2448       In this example we contact a secondary in the replica  set  and  do  an
2449       "inline" map reduce, so the results are returned immediately:
2450
2451       map-reduce-advanced.c
2452
2453          bool
2454          map_reduce_advanced (mongoc_database_t *database)
2455          {
2456             bson_t *command;
2457             bson_error_t error;
2458             bool res = true;
2459             mongoc_cursor_t *cursor;
2460             mongoc_read_prefs_t *read_pref;
2461             const bson_t *doc;
2462
2463             /* Construct the mapReduce command */
2464             /* Other arguments can also be specified here, like "query" or "limit"
2465                and so on */
2466
2467             /* Read the results inline from a secondary replica */
2468             command = BCON_NEW ("mapReduce",
2469                                 BCON_UTF8 (COLLECTION_NAME),
2470                                 "map",
2471                                 BCON_CODE (MAPPER),
2472                                 "reduce",
2473                                 BCON_CODE (REDUCER),
2474                                 "out",
2475                                 "{",
2476                                 "inline",
2477                                 "1",
2478                                 "}");
2479
2480             read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
2481             cursor = mongoc_database_command (
2482                database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref);
2483
2484             /* Do something with the results */
2485             while (mongoc_cursor_next (cursor, &doc)) {
2486                print_res (doc);
2487             }
2488
2489             if (mongoc_cursor_error (cursor, &error)) {
2490                fprintf (stderr, "ERROR: %s\n", error.message);
2491                res = false;
2492             }
2493
2494             mongoc_cursor_destroy (cursor);
2495             mongoc_read_prefs_destroy (read_pref);
2496             bson_destroy (command);
2497
2498             return res;
2499          }
2500
2501
2502   Running the Examples
2503       Here's how to run the example code
2504
2505       basic-aggregation.c
2506
2507          /*
2508           * Copyright 2016 MongoDB, Inc.
2509           *
2510           * Licensed under the Apache License, Version 2.0 (the "License");
2511           * you may not use this file except in compliance with the License.
2512           * You may obtain a copy of the License at
2513           *
2514           *   http://www.apache.org/licenses/LICENSE-2.0
2515           *
2516           * Unless required by applicable law or agreed to in writing, software
2517           * distributed under the License is distributed on an "AS IS" BASIS,
2518           * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2519           * See the License for the specific language governing permissions and
2520           * limitations under the License.
2521           */
2522
2523
2524          #include <mongoc/mongoc.h>
2525          #include <stdio.h>
2526
2527
2528          #include "constants.c"
2529
2530          #include "../doc-common-insert.c"
2531          #include "distinct.c"
2532          #include "map-reduce-basic.c"
2533          #include "map-reduce-advanced.c"
2534
2535
2536          int
2537          main (int argc, char *argv[])
2538          {
2539             mongoc_database_t *database = NULL;
2540             mongoc_client_t *client = NULL;
2541             mongoc_collection_t *collection = NULL;
2542             mongoc_uri_t *uri = NULL;
2543             bson_error_t error;
2544             char *host_and_port = NULL;
2545             int exit_code = EXIT_FAILURE;
2546
2547             if (argc != 2) {
2548                fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]);
2549                fprintf (stderr,
2550                         "the connection string can be of the following forms:\n");
2551                fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
2552                fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
2553                fprintf (stderr,
2554                         "mongodb://user:pass@localhost:27017\t"
2555                         "local machine on port 27017, and authenticate with username "
2556                         "user and password pass\n");
2557                return exit_code;
2558             }
2559
2560             mongoc_init ();
2561
2562             if (strncmp (argv[1], "mongodb://", 10) == 0) {
2563                host_and_port = bson_strdup (argv[1]);
2564             } else {
2565                host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
2566             }
2567
2568             uri = mongoc_uri_new_with_error (host_and_port, &error);
2569             if (!uri) {
2570                fprintf (stderr,
2571                         "failed to parse URI: %s\n"
2572                         "error message:       %s\n",
2573                         host_and_port,
2574                         error.message);
2575                goto cleanup;
2576             }
2577
2578             client = mongoc_client_new_from_uri (uri);
2579             if (!client) {
2580                goto cleanup;
2581             }
2582
2583             mongoc_client_set_error_api (client, 2);
2584             database = mongoc_client_get_database (client, "test");
2585             collection = mongoc_database_get_collection (database, COLLECTION_NAME);
2586
2587             printf ("Inserting data\n");
2588             if (!insert_data (collection)) {
2589                goto cleanup;
2590             }
2591
2592             printf ("distinct\n");
2593             if (!distinct (database)) {
2594                goto cleanup;
2595             }
2596
2597             printf ("map reduce\n");
2598             if (!map_reduce_basic (database)) {
2599                goto cleanup;
2600             }
2601
2602             printf ("more complicated map reduce\n");
2603             if (!map_reduce_advanced (database)) {
2604                goto cleanup;
2605             }
2606
2607             exit_code = EXIT_SUCCESS;
2608
2609          cleanup:
2610             if (collection) {
2611                mongoc_collection_destroy (collection);
2612             }
2613
2614             if (database) {
2615                mongoc_database_destroy (database);
2616             }
2617
2618             if (client) {
2619                mongoc_client_destroy (client);
2620             }
2621
2622             if (uri) {
2623                mongoc_uri_destroy (uri);
2624             }
2625
2626             if (host_and_port) {
2627                bson_free (host_and_port);
2628             }
2629
2630             mongoc_cleanup ();
2631             return exit_code;
2632          }
2633
2634
2635       If  you  want  to try the advanced map reduce example with a secondary,
2636       start a replica set (instructions for how  to  do  this  can  be  found
2637       here).
2638
2639       Otherwise, just start an instance of MongoDB:
2640
2641          $ mongod
2642
2643       Now compile and run the example program:
2644
2645          $ cd examples/basic_aggregation/
2646          $ gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0)
2647          $ ./agg-example localhost
2648
2649          Inserting data
2650          distinct
2651          Next double: 2.000000
2652          Next double: 3.000000
2653          map reduce
2654          { "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
2655          { "_id" : "cat", "value" : 63 }
2656          { "_id" : "dog", "value" : 42 }
2657          { "_id" : "mouse", "value" : 21 }
2658          more complicated map reduce
2659          { "results" : [ { "_id" : "cat", "value" : 63 }, { "_id" : "dog", "value" : 42 }, { "_id" : "mouse", "value" : 21 } ], "timeMillis" : 14, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
2660

USING LIBMONGOC IN A MICROSOFT VISUAL STUDIO PROJECT

2662       Download and install libmongoc on your system, then open Visual Studio,
2663       select "File→New→Project...", and create a new Win32  Console  Applica‐
2664       tion.  [image]
2665
2666       Remember to switch the platform from 32-bit to 64-bit: [image]
2667
2668       Right-click  on  your  console application in the Solution Explorer and
2669       select "Properties". Choose to  edit  properties  for  "All  Configura‐
2670       tions",  expand  the  "C/C++"  options and choose "General". Add to the
2671       "Additional Include Directories" these paths:
2672
2673          C:\mongo-c-driver\include\libbson-1.0
2674          C:\mongo-c-driver\include\libmongoc-1.0
2675       [image]
2676
2677       (If you chose a different CMAKE_INSTALL_PREFIX when you ran CMake, your
2678       include paths will be different.)
2679
2680       Also  in  the Properties dialog, expand the "Linker" options and choose
2681       "Input", and add to the "Additional Dependencies" these libraries:
2682
2683          C:\mongo-c-driver\lib\bson-1.0.lib
2684          C:\mongo-c-driver\lib\mongoc-1.0.lib
2685       [image]
2686
2687       Adding these libraries as dependencies provides linker symbols to build
2688       your  application,  but  to  actually run it, libbson's and libmongoc's
2689       DLLs must be in your executable path. Select "Debugging" in the Proper‐
2690       ties dialog, and set the "Environment" option to:
2691
2692          PATH=c:/mongo-c-driver/bin
2693       [image]
2694
2695       Finally, include "mongoc/mongoc.h" in your project's "stdafx.h":
2696
2697          #include <mongoc/mongoc.h>
2698
2699   Static linking
2700       Following  the instructions above, you have dynamically linked your ap‐
2701       plication to the libbson and libmongoc DLLs. This is usually the  right
2702       choice. If you want to link statically instead, update your "Additional
2703       Dependencies" list by removing bson-1.0.lib and mongoc-1.0.lib and  re‐
2704       placing them with these libraries:
2705
2706          C:\mongo-c-driver\lib\bson-static-1.0.lib
2707          C:\mongo-c-driver\lib\mongoc-static-1.0.lib
2708          ws2_32.lib
2709          Secur32.lib
2710          Crypt32.lib
2711          BCrypt.lib
2712       [image]
2713
2714       (To  explain  the purpose of each library: bson-static-1.0.lib and mon‐
2715       goc-static-1.0.lib are static archives of the driver code.  The  socket
2716       library  ws2_32  is  required by libbson, which uses the socket routine
2717       gethostname to help guarantee ObjectId uniqueness. The  BCrypt  library
2718       is  used  by  libmongoc for TLS connections to MongoDB, and Secur32 and
2719       Crypt32 are required for enterprise authentication  methods  like  Ker‐
2720       beros.)
2721
2722       Finally,  define  two preprocessor symbols before including mongoc/mon‐
2723       goc.h in your stdafx.h:
2724
2725          #define BSON_STATIC
2726          #define MONGOC_STATIC
2727          #include <mongoc/mongoc.h>
2728
2729       Making these changes to your project is only required for static  link‐
2730       ing;  for  most people, the dynamic-linking instructions above are pre‐
2731       ferred.
2732
2733   Next Steps
2734       Now you can build and debug applications  in  Visual  Studio  that  use
2735       libbson  and  libmongoc. Proceed to Making a Connection in the tutorial
2736       to learn how connect to MongoDB and perform operations.
2737

MANAGE COLLECTION INDEXES

2739       To    create    indexes    on     a     MongoDB     collection,     use
2740       mongoc_collection_create_indexes_with_opts():
2741
2742          // `keys` represents an ascending index on field `x`.
2743          bson_t *keys = BCON_NEW ("x", BCON_INT32 (1));
2744          mongoc_index_model_t *im = mongoc_index_model_new (keys, NULL /* opts */);
2745          if (mongoc_collection_create_indexes_with_opts (
2746                 coll, &im, 1, NULL /* opts */, NULL /* reply */, &error)) {
2747             printf ("Successfully created index\n");
2748          } else {
2749             bson_destroy (keys);
2750             HANDLE_ERROR ("Failed to create index: %s", error.message);
2751          }
2752          bson_destroy (keys);
2753
2754
2755       To list indexes, use mongoc_collection_find_indexes_with_opts():
2756
2757          mongoc_cursor_t *cursor =
2758             mongoc_collection_find_indexes_with_opts (coll, NULL /* opts */);
2759          printf ("Listing indexes:\n");
2760          const bson_t *got;
2761          while (mongoc_cursor_next (cursor, &got)) {
2762             char *got_str = bson_as_canonical_extended_json (got, NULL);
2763             printf ("  %s\n", got_str);
2764             bson_free (got_str);
2765          }
2766          if (mongoc_cursor_error (cursor, &error)) {
2767             mongoc_cursor_destroy (cursor);
2768             HANDLE_ERROR ("Failed to list indexes: %s", error.message);
2769          }
2770          mongoc_cursor_destroy (cursor);
2771
2772
2773       To drop an index, use mongoc_collection_drop_index_with_opts(). The in‐
2774       dex   name   may   be   obtained   from   the   keys   document    with
2775       mongoc_collection_keys_to_index_string():
2776
2777          bson_t *keys = BCON_NEW ("x", BCON_INT32 (1));
2778          char *index_name = mongoc_collection_keys_to_index_string (keys);
2779          if (mongoc_collection_drop_index_with_opts (
2780                 coll, index_name, NULL /* opts */, &error)) {
2781             printf ("Successfully dropped index\n");
2782          } else {
2783             bson_free (index_name);
2784             bson_destroy (keys);
2785             HANDLE_ERROR ("Failed to drop index: %s", error.message);
2786          }
2787          bson_free (index_name);
2788          bson_destroy (keys);
2789
2790
2791       For a full example, see example-manage-collection-indexes.c.
2792

AIDS FOR DEBUGGING

2794   GDB
2795       This repository contains a .gdbinit file that contains helper functions
2796       to  aid  debugging  of  data  structures.  GDB  will  load  this   file
2797       automatically  if  you  have  added  the  directory  which contains the
2798       .gdbinit file to GDB's auto-load safe-path, and you start GDB from  the
2799       directory which holds the .gdbinit file.
2800
2801       You  can  see  the  safe-path  with  show  auto-load safe-path on a GDB
2802       prompt. You can configure it by setting it in ~/.gdbinit with:
2803
2804          add-auto-load-safe-path /path/to/mongo-c-driver
2805
2806       If you haven't added the path to your auto-load safe-path, or start GDB
2807       in another directory, load the file with:
2808
2809          source path/to/mongo-c-driver/.gdbinit
2810
2811       The  .gdbinit file defines the printbson function, which shows the con‐
2812       tents of a bson_t * variable.  If you have a  local  bson_t,  then  you
2813       must prefix the variable with a &.
2814
2815       An example GDB session looks like:
2816
2817          (gdb) printbson bson
2818          ALLOC [0x555556cd7310 + 0] (len=475)
2819          {
2820              'bool' : true,
2821              'int32' : NumberInt("42"),
2822              'int64' : NumberLong("3000000042"),
2823              'string' : "Stŕìñg",
2824              'objectId' : ObjectID("5A1442F3122D331C3C6757E1"),
2825              'utcDateTime' : UTCDateTime(1511277299031),
2826              'arrayOfInts' : [
2827                  '0' : NumberInt("1"),
2828                  '1' : NumberInt("2")
2829              ],
2830              'embeddedDocument' : {
2831                  'arrayOfStrings' : [
2832                      '0' : "one",
2833                      '1' : "two"
2834                  ],
2835                  'double' : 2.718280,
2836                  'notherDoc' : {
2837                      'true' : NumberInt("1"),
2838                      'false' : false
2839                  }
2840              },
2841              'binary' : Binary("02", "3031343532333637"),
2842              'regex' : Regex("@[a-z]+@", "im"),
2843              'null' : null,
2844              'js' : JavaScript("print foo"),
2845              'jsws' : JavaScript("print foo") with scope: {
2846                  'f' : NumberInt("42"),
2847                  'a' : [
2848                      '0' : 3.141593,
2849                      '1' : 2.718282
2850                  ]
2851              },
2852              'timestamp' : Timestamp(4294967295, 4294967295),
2853              'double' : 3.141593
2854          }
2855
2856   LLDB
2857       The  mongo-c-driver  repository contains a script lldb_bson.py that can
2858       be imported into an LLDB sessions and allows rich  inspection  of  BSON
2859       values.
2860
2861       NOTE:
2862          The lldb_bson.py module requires an LLDB with Python 3.8 or newer.
2863
2864       To activate the script, import it from the LLDB command line:
2865
2866          (lldb) command script import /path/to/mongo-c-driver/lldb_bson.py
2867
2868       Upon  success,  the  message  lldb_bson is ready will be printed to the
2869       LLDB console.
2870
2871       The import of this script can be made automatic by adding  the  command
2872       to  an  .lldbinit file. For example: Create a file ~/.lldbinit contain‐
2873       ing:
2874
2875          command script import /path/to/mongo-c-driver/lldb_bson.py
2876
2877       The docstring at the top of the lldb_bson.py file contains more  infor‐
2878       mation on the capabilities of the module.
2879
2880   Debug assertions
2881       To  enable  runtime debug assertions, configure with -DENABLE_DEBUG_AS‐
2882       SERTIONS=ON.
2883

IN-USE ENCRYPTION

2885       In-Use Encryption consists of two features:
2886
2887   Client-Side Field Level Encryption
2888       New in MongoDB 4.2, Client-Side Field Level Encryption  (also  referred
2889       to  as  CSFLE) allows administrators and developers to encrypt specific
2890       data fields in addition to other MongoDB encryption features.
2891
2892       With CSFLE, developers can  encrypt  fields  client  side  without  any
2893       server-side configuration or directives. CSFLE supports workloads where
2894       applications must guarantee that unauthorized parties, including server
2895       administrators, cannot read the encrypted data.
2896
2897       Automatic  encryption, where sensitive fields in commands are encrypted
2898       automatically, requires an Enterprise-only dependency for Query  Analy‐
2899       sis. See In-Use Encryption for more information.
2900
2901       SEE ALSO:
2902          The MongoDB Manual for Client-Side Field Level Encryption
2903
2904
2905   Automatic Client-Side Field Level Encryption
2906       Automatic       encryption       is       enabled       by      calling
2907       mongoc_client_enable_auto_encryption() on a mongoc_client_t.  The  fol‐
2908       lowing   examples  show  how  to  set  up  automatic  encryption  using
2909       mongoc_client_encryption_t to create a new encryption data key.
2910
2911       NOTE:
2912          Automatic encryption requires MongoDB 4.2 enterprise  or  a  MongoDB
2913          4.2  Atlas cluster. The community version of the server supports au‐
2914          tomatic decryption as well as Explicit Encryption.
2915
2916   Providing Local Automatic Encryption Rules
2917       The following example shows how to specify automatic  encryption  rules
2918       using          a          schema          map          set         with
2919       mongoc_auto_encryption_opts_set_schema_map(). The automatic  encryption
2920       rules are expressed using a strict subset of the JSON Schema syntax.
2921
2922       Supplying  a  schema  map  provides  more security than relying on JSON
2923       Schemas obtained from the  server.  It  protects  against  a  malicious
2924       server  advertising  a  false JSON Schema, which could trick the client
2925       into sending unencrypted data that should be encrypted.
2926
2927       JSON Schemas supplied in the schema map only apply to configuring auto‐
2928       matic encryption. Other validation rules in the JSON schema will not be
2929       enforced by the driver and will result in an error:
2930
2931       client-side-encryption-schema-map.c
2932
2933          #include <mongoc/mongoc.h>
2934          #include <stdio.h>
2935          #include <stdlib.h>
2936
2937          #include "client-side-encryption-helpers.h"
2938
2939          /* Helper method to create a new data key in the key vault, a schema to use that
2940           * key, and writes the schema to a file for later use. */
2941          static bool
2942          create_schema_file (bson_t *kms_providers,
2943                              const char *keyvault_db,
2944                              const char *keyvault_coll,
2945                              mongoc_client_t *keyvault_client,
2946                              bson_error_t *error)
2947          {
2948             mongoc_client_encryption_t *client_encryption = NULL;
2949             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
2950             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
2951             bson_value_t datakey_id = {0};
2952             char *keyaltnames[] = {"mongoc_encryption_example_1"};
2953             bson_t *schema = NULL;
2954             char *schema_string = NULL;
2955             size_t schema_string_len;
2956             FILE *outfile = NULL;
2957             bool ret = false;
2958
2959             client_encryption_opts = mongoc_client_encryption_opts_new ();
2960             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
2961                                                              kms_providers);
2962             mongoc_client_encryption_opts_set_keyvault_namespace (
2963                client_encryption_opts, keyvault_db, keyvault_coll);
2964             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
2965                                                                keyvault_client);
2966
2967             client_encryption =
2968                mongoc_client_encryption_new (client_encryption_opts, error);
2969             if (!client_encryption) {
2970                goto fail;
2971             }
2972
2973             /* Create a new data key and json schema for the encryptedField.
2974              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
2975              */
2976             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
2977             mongoc_client_encryption_datakey_opts_set_keyaltnames (
2978                datakey_opts, keyaltnames, 1);
2979             if (!mongoc_client_encryption_create_datakey (
2980                    client_encryption, "local", datakey_opts, &datakey_id, error)) {
2981                goto fail;
2982             }
2983
2984             /* Create a schema describing that "encryptedField" is a string encrypted
2985              * with the newly created data key using deterministic encryption. */
2986             schema = BCON_NEW ("properties",
2987                                "{",
2988                                "encryptedField",
2989                                "{",
2990                                "encrypt",
2991                                "{",
2992                                "keyId",
2993                                "[",
2994                                BCON_BIN (datakey_id.value.v_binary.subtype,
2995                                          datakey_id.value.v_binary.data,
2996                                          datakey_id.value.v_binary.data_len),
2997                                "]",
2998                                "bsonType",
2999                                "string",
3000                                "algorithm",
3001                                MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3002                                "}",
3003                                "}",
3004                                "}",
3005                                "bsonType",
3006                                "object");
3007
3008             /* Use canonical JSON so that other drivers and tools will be
3009              * able to parse the MongoDB extended JSON file. */
3010             schema_string = bson_as_canonical_extended_json (schema, &schema_string_len);
3011             outfile = fopen ("jsonSchema.json", "w");
3012             if (0 == fwrite (schema_string, sizeof (char), schema_string_len, outfile)) {
3013                fprintf (stderr, "failed to write to file\n");
3014                goto fail;
3015             }
3016
3017             ret = true;
3018          fail:
3019             mongoc_client_encryption_destroy (client_encryption);
3020             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3021             mongoc_client_encryption_opts_destroy (client_encryption_opts);
3022             bson_free (schema_string);
3023             bson_destroy (schema);
3024             bson_value_destroy (&datakey_id);
3025             if (outfile) {
3026                fclose (outfile);
3027             }
3028             return ret;
3029          }
3030
3031          /* This example demonstrates how to use automatic encryption with a client-side
3032           * schema map using the enterprise version of MongoDB */
3033          int
3034          main (void)
3035          {
3036          /* The collection used to store the encryption data keys. */
3037          #define KEYVAULT_DB "encryption"
3038          #define KEYVAULT_COLL "__libmongocTestKeyVault"
3039          /* The collection used to store the encrypted documents in this example. */
3040          #define ENCRYPTED_DB "test"
3041          #define ENCRYPTED_COLL "coll"
3042
3043             int exit_status = EXIT_FAILURE;
3044             bool ret;
3045             uint8_t *local_masterkey = NULL;
3046             uint32_t local_masterkey_len;
3047             bson_t *kms_providers = NULL;
3048             bson_error_t error = {0};
3049             bson_t *index_keys = NULL;
3050             bson_t *index_opts = NULL;
3051             mongoc_index_model_t *index_model = NULL;
3052             bson_json_reader_t *reader = NULL;
3053             bson_t schema = BSON_INITIALIZER;
3054             bson_t *schema_map = NULL;
3055
3056             /* The MongoClient used to access the key vault (keyvault_namespace). */
3057             mongoc_client_t *keyvault_client = NULL;
3058             mongoc_collection_t *keyvault_coll = NULL;
3059             mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3060             mongoc_client_t *client = NULL;
3061             mongoc_collection_t *coll = NULL;
3062             bson_t *to_insert = NULL;
3063             mongoc_client_t *unencrypted_client = NULL;
3064             mongoc_collection_t *unencrypted_coll = NULL;
3065
3066             mongoc_init ();
3067
3068             /* Configure the master key. This must be the same master key that was used
3069              * to create the encryption key. */
3070             local_masterkey =
3071                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3072             if (!local_masterkey || local_masterkey_len != 96) {
3073                fprintf (stderr,
3074                         "Specify LOCAL_MASTERKEY environment variable as a "
3075                         "secure random 96 byte hex value.\n");
3076                goto fail;
3077             }
3078
3079             kms_providers = BCON_NEW ("local",
3080                                       "{",
3081                                       "key",
3082                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
3083                                       "}");
3084
3085             /* Set up the key vault for this example. */
3086             keyvault_client = mongoc_client_new (
3087                "mongodb://localhost/?appname=client-side-encryption-keyvault");
3088             BSON_ASSERT (keyvault_client);
3089
3090             keyvault_coll = mongoc_client_get_collection (
3091                keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3092             mongoc_collection_drop (keyvault_coll, NULL);
3093
3094             /* Create a unique index to ensure that two data keys cannot share the same
3095              * keyAltName. This is recommended practice for the key vault. */
3096             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3097             index_opts = BCON_NEW ("unique",
3098                                    BCON_BOOL (true),
3099                                    "partialFilterExpression",
3100                                    "{",
3101                                    "keyAltNames",
3102                                    "{",
3103                                    "$exists",
3104                                    BCON_BOOL (true),
3105                                    "}",
3106                                    "}");
3107             index_model = mongoc_index_model_new (index_keys, index_opts);
3108             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
3109                                                               &index_model,
3110                                                               1,
3111                                                               NULL /* opts */,
3112                                                               NULL /* reply */,
3113                                                               &error);
3114
3115             if (!ret) {
3116                goto fail;
3117             }
3118
3119             /* Create a new data key and a schema using it for encryption. Save the
3120              * schema to the file jsonSchema.json */
3121             ret = create_schema_file (
3122                kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3123
3124             if (!ret) {
3125                goto fail;
3126             }
3127
3128             /* Load the JSON Schema and construct the local schema_map option. */
3129             reader = bson_json_reader_new_from_file ("jsonSchema.json", &error);
3130             if (!reader) {
3131                goto fail;
3132             }
3133
3134             bson_json_reader_read (reader, &schema, &error);
3135
3136             /* Construct the schema map, mapping the namespace of the collection to the
3137              * schema describing encryption. */
3138             schema_map =
3139                BCON_NEW (ENCRYPTED_DB "." ENCRYPTED_COLL, BCON_DOCUMENT (&schema));
3140
3141             auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3142             mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3143                                                              keyvault_client);
3144             mongoc_auto_encryption_opts_set_keyvault_namespace (
3145                auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3146             mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3147                                                            kms_providers);
3148             mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts,
3149                                                         schema_map);
3150
3151             client =
3152                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3153             BSON_ASSERT (client);
3154
3155             /* Enable automatic encryption. It will determine that encryption is
3156              * necessary from the schema map instead of relying on the server to provide
3157              * a schema. */
3158             ret = mongoc_client_enable_auto_encryption (
3159                client, auto_encryption_opts, &error);
3160             if (!ret) {
3161                goto fail;
3162             }
3163
3164             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3165
3166             /* Clear old data */
3167             mongoc_collection_drop (coll, NULL);
3168
3169             to_insert = BCON_NEW ("encryptedField", "123456789");
3170             ret = mongoc_collection_insert_one (
3171                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3172             if (!ret) {
3173                goto fail;
3174             }
3175             printf ("decrypted document: ");
3176             if (!print_one_document (coll, &error)) {
3177                goto fail;
3178             }
3179             printf ("\n");
3180
3181             unencrypted_client = mongoc_client_new (
3182                "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3183             BSON_ASSERT (unencrypted_client);
3184
3185             unencrypted_coll = mongoc_client_get_collection (
3186                unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3187             printf ("encrypted document: ");
3188             if (!print_one_document (unencrypted_coll, &error)) {
3189                goto fail;
3190             }
3191             printf ("\n");
3192
3193             exit_status = EXIT_SUCCESS;
3194          fail:
3195             if (error.code) {
3196                fprintf (stderr, "error: %s\n", error.message);
3197             }
3198
3199             bson_free (local_masterkey);
3200             bson_destroy (kms_providers);
3201             mongoc_collection_destroy (keyvault_coll);
3202             mongoc_index_model_destroy (index_model);
3203             bson_destroy (index_opts);
3204             bson_destroy (index_keys);
3205             bson_json_reader_destroy (reader);
3206             mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3207             mongoc_collection_destroy (coll);
3208             mongoc_client_destroy (client);
3209             bson_destroy (to_insert);
3210             mongoc_collection_destroy (unencrypted_coll);
3211             mongoc_client_destroy (unencrypted_client);
3212             mongoc_client_destroy (keyvault_client);
3213             bson_destroy (&schema);
3214             bson_destroy (schema_map);
3215             mongoc_cleanup ();
3216             return exit_status;
3217          }
3218
3219
3220   Server-Side Field Level Encryption Enforcement
3221       The MongoDB 4.2 server supports using schema validation to enforce  en‐
3222       cryption  of  specific  fields  in a collection. This schema validation
3223       will prevent an application from inserting unencrypted values  for  any
3224       fields marked with the "encrypt" JSON schema keyword.
3225
3226       The  following  example  shows how to set up automatic encryption using
3227       mongoc_client_encryption_t to create a new encryption data key and cre‐
3228       ate a collection with the necessary JSON Schema:
3229
3230       client-side-encryption-server-schema.c
3231
3232          #include <mongoc/mongoc.h>
3233          #include <stdio.h>
3234          #include <stdlib.h>
3235
3236          #include "client-side-encryption-helpers.h"
3237
3238          /* Helper method to create and return a JSON schema to use for encryption.
3239          The caller will use the returned schema for server-side encryption validation.
3240          */
3241          static bson_t *
3242          create_schema (bson_t *kms_providers,
3243                         const char *keyvault_db,
3244                         const char *keyvault_coll,
3245                         mongoc_client_t *keyvault_client,
3246                         bson_error_t *error)
3247          {
3248             mongoc_client_encryption_t *client_encryption = NULL;
3249             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3250             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3251             bson_value_t datakey_id = {0};
3252             char *keyaltnames[] = {"mongoc_encryption_example_2"};
3253             bson_t *schema = NULL;
3254
3255             client_encryption_opts = mongoc_client_encryption_opts_new ();
3256             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3257                                                              kms_providers);
3258             mongoc_client_encryption_opts_set_keyvault_namespace (
3259                client_encryption_opts, keyvault_db, keyvault_coll);
3260             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3261                                                                keyvault_client);
3262
3263             client_encryption =
3264                mongoc_client_encryption_new (client_encryption_opts, error);
3265             if (!client_encryption) {
3266                goto fail;
3267             }
3268
3269             /* Create a new data key and json schema for the encryptedField.
3270              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3271              */
3272             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3273             mongoc_client_encryption_datakey_opts_set_keyaltnames (
3274                datakey_opts, keyaltnames, 1);
3275             if (!mongoc_client_encryption_create_datakey (
3276                    client_encryption, "local", datakey_opts, &datakey_id, error)) {
3277                goto fail;
3278             }
3279
3280             /* Create a schema describing that "encryptedField" is a string encrypted
3281              * with the newly created data key using deterministic encryption. */
3282             schema = BCON_NEW ("properties",
3283                                "{",
3284                                "encryptedField",
3285                                "{",
3286                                "encrypt",
3287                                "{",
3288                                "keyId",
3289                                "[",
3290                                BCON_BIN (datakey_id.value.v_binary.subtype,
3291                                          datakey_id.value.v_binary.data,
3292                                          datakey_id.value.v_binary.data_len),
3293                                "]",
3294                                "bsonType",
3295                                "string",
3296                                "algorithm",
3297                                MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3298                                "}",
3299                                "}",
3300                                "}",
3301                                "bsonType",
3302                                "object");
3303
3304          fail:
3305             mongoc_client_encryption_destroy (client_encryption);
3306             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3307             mongoc_client_encryption_opts_destroy (client_encryption_opts);
3308             bson_value_destroy (&datakey_id);
3309             return schema;
3310          }
3311
3312          /* This example demonstrates how to use automatic encryption with a server-side
3313           * schema using the enterprise version of MongoDB */
3314          int
3315          main (void)
3316          {
3317          /* The collection used to store the encryption data keys. */
3318          #define KEYVAULT_DB "encryption"
3319          #define KEYVAULT_COLL "__libmongocTestKeyVault"
3320          /* The collection used to store the encrypted documents in this example. */
3321          #define ENCRYPTED_DB "test"
3322          #define ENCRYPTED_COLL "coll"
3323
3324             int exit_status = EXIT_FAILURE;
3325             bool ret;
3326             uint8_t *local_masterkey = NULL;
3327             uint32_t local_masterkey_len;
3328             bson_t *kms_providers = NULL;
3329             bson_error_t error = {0};
3330             bson_t *index_keys = NULL;
3331             bson_t *index_opts = NULL;
3332             mongoc_index_model_t *index_model = NULL;
3333             bson_json_reader_t *reader = NULL;
3334             bson_t *schema = NULL;
3335
3336             /* The MongoClient used to access the key vault (keyvault_namespace). */
3337             mongoc_client_t *keyvault_client = NULL;
3338             mongoc_collection_t *keyvault_coll = NULL;
3339             mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3340             mongoc_client_t *client = NULL;
3341             mongoc_collection_t *coll = NULL;
3342             bson_t *to_insert = NULL;
3343             mongoc_client_t *unencrypted_client = NULL;
3344             mongoc_collection_t *unencrypted_coll = NULL;
3345             bson_t *create_cmd = NULL;
3346             bson_t *create_cmd_opts = NULL;
3347             mongoc_write_concern_t *wc = NULL;
3348
3349             mongoc_init ();
3350
3351             /* Configure the master key. This must be the same master key that was used
3352              * to create
3353              * the encryption key. */
3354             local_masterkey =
3355                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3356             if (!local_masterkey || local_masterkey_len != 96) {
3357                fprintf (stderr,
3358                         "Specify LOCAL_MASTERKEY environment variable as a "
3359                         "secure random 96 byte hex value.\n");
3360                goto fail;
3361             }
3362
3363             kms_providers = BCON_NEW ("local",
3364                                       "{",
3365                                       "key",
3366                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
3367                                       "}");
3368
3369             /* Set up the key vault for this example. */
3370             keyvault_client = mongoc_client_new (
3371                "mongodb://localhost/?appname=client-side-encryption-keyvault");
3372             BSON_ASSERT (keyvault_client);
3373
3374             keyvault_coll = mongoc_client_get_collection (
3375                keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
3376             mongoc_collection_drop (keyvault_coll, NULL);
3377
3378             /* Create a unique index to ensure that two data keys cannot share the same
3379              * keyAltName. This is recommended practice for the key vault. */
3380             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3381             index_opts = BCON_NEW ("unique",
3382                                    BCON_BOOL (true),
3383                                    "partialFilterExpression",
3384                                    "{",
3385                                    "keyAltNames",
3386                                    "{",
3387                                    "$exists",
3388                                    BCON_BOOL (true),
3389                                    "}",
3390                                    "}");
3391             index_model = mongoc_index_model_new (index_keys, index_opts);
3392             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
3393                                                               &index_model,
3394                                                               1,
3395                                                               NULL /* opts */,
3396                                                               NULL /* reply */,
3397                                                               &error);
3398
3399             if (!ret) {
3400                goto fail;
3401             }
3402
3403             auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3404             mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
3405                                                              keyvault_client);
3406             mongoc_auto_encryption_opts_set_keyvault_namespace (
3407                auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3408             mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3409                                                            kms_providers);
3410             schema = create_schema (
3411                kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);
3412
3413             if (!schema) {
3414                goto fail;
3415             }
3416
3417             client =
3418                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3419             BSON_ASSERT (client);
3420
3421             ret = mongoc_client_enable_auto_encryption (
3422                client, auto_encryption_opts, &error);
3423             if (!ret) {
3424                goto fail;
3425             }
3426
3427             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3428
3429             /* Clear old data */
3430             mongoc_collection_drop (coll, NULL);
3431
3432             /* Create the collection with the encryption JSON Schema. */
3433             create_cmd = BCON_NEW ("create",
3434                                    ENCRYPTED_COLL,
3435                                    "validator",
3436                                    "{",
3437                                    "$jsonSchema",
3438                                    BCON_DOCUMENT (schema),
3439                                    "}");
3440             wc = mongoc_write_concern_new ();
3441             mongoc_write_concern_set_wmajority (wc, 0);
3442             create_cmd_opts = bson_new ();
3443             mongoc_write_concern_append (wc, create_cmd_opts);
3444             ret = mongoc_client_command_with_opts (client,
3445                                                    ENCRYPTED_DB,
3446                                                    create_cmd,
3447                                                    NULL /* read prefs */,
3448                                                    create_cmd_opts,
3449                                                    NULL /* reply */,
3450                                                    &error);
3451             if (!ret) {
3452                goto fail;
3453             }
3454
3455             to_insert = BCON_NEW ("encryptedField", "123456789");
3456             ret = mongoc_collection_insert_one (
3457                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3458             if (!ret) {
3459                goto fail;
3460             }
3461             printf ("decrypted document: ");
3462             if (!print_one_document (coll, &error)) {
3463                goto fail;
3464             }
3465             printf ("\n");
3466
3467             unencrypted_client = mongoc_client_new (
3468                "mongodb://localhost/?appname=client-side-encryption-unencrypted");
3469             BSON_ASSERT (unencrypted_client);
3470
3471             unencrypted_coll = mongoc_client_get_collection (
3472                unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3473             printf ("encrypted document: ");
3474             if (!print_one_document (unencrypted_coll, &error)) {
3475                goto fail;
3476             }
3477             printf ("\n");
3478
3479             /* Expect a server-side error if inserting with the unencrypted collection.
3480              */
3481             ret = mongoc_collection_insert_one (
3482                unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3483             if (!ret) {
3484                printf ("insert with unencrypted collection failed: %s\n", error.message);
3485                memset (&error, 0, sizeof (error));
3486             }
3487
3488             exit_status = EXIT_SUCCESS;
3489          fail:
3490             if (error.code) {
3491                fprintf (stderr, "error: %s\n", error.message);
3492             }
3493
3494             bson_free (local_masterkey);
3495             bson_destroy (kms_providers);
3496             mongoc_collection_destroy (keyvault_coll);
3497             mongoc_index_model_destroy (index_model);
3498             bson_destroy (index_opts);
3499             bson_destroy (index_keys);
3500             bson_json_reader_destroy (reader);
3501             mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3502             mongoc_collection_destroy (coll);
3503             mongoc_client_destroy (client);
3504             bson_destroy (to_insert);
3505             mongoc_collection_destroy (unencrypted_coll);
3506             mongoc_client_destroy (unencrypted_client);
3507             mongoc_client_destroy (keyvault_client);
3508             bson_destroy (schema);
3509             bson_destroy (create_cmd);
3510             bson_destroy (create_cmd_opts);
3511             mongoc_write_concern_destroy (wc);
3512
3513             mongoc_cleanup ();
3514             return exit_status;
3515          }
3516
3517
3518   Explicit Encryption
3519       Explicit  encryption  is  a  MongoDB community feature and does not use
3520       Query Analysis (mongocryptd or crypt_shared).  Explicit  encryption  is
3521       provided by the mongoc_client_encryption_t class, for example:
3522
3523       client-side-encryption-explicit.c
3524
3525          #include <mongoc/mongoc.h>
3526          #include <stdio.h>
3527          #include <stdlib.h>
3528
3529          #include "client-side-encryption-helpers.h"
3530
3531          /* This example demonstrates how to use explicit encryption and decryption using
3532           * the community version of MongoDB */
3533          int
3534          main (void)
3535          {
3536          /* The collection used to store the encryption data keys. */
3537          #define KEYVAULT_DB "encryption"
3538          #define KEYVAULT_COLL "__libmongocTestKeyVault"
3539          /* The collection used to store the encrypted documents in this example. */
3540          #define ENCRYPTED_DB "test"
3541          #define ENCRYPTED_COLL "coll"
3542
3543             int exit_status = EXIT_FAILURE;
3544             bool ret;
3545             uint8_t *local_masterkey = NULL;
3546             uint32_t local_masterkey_len;
3547             bson_t *kms_providers = NULL;
3548             bson_error_t error = {0};
3549             bson_t *index_keys = NULL;
3550             bson_t *index_opts = NULL;
3551             mongoc_index_model_t *index_model = NULL;
3552             bson_t *schema = NULL;
3553             mongoc_client_t *client = NULL;
3554             mongoc_collection_t *coll = NULL;
3555             mongoc_collection_t *keyvault_coll = NULL;
3556             bson_t *to_insert = NULL;
3557             bson_t *create_cmd = NULL;
3558             bson_t *create_cmd_opts = NULL;
3559             mongoc_write_concern_t *wc = NULL;
3560             mongoc_client_encryption_t *client_encryption = NULL;
3561             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3562             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3563             char *keyaltnames[] = {"mongoc_encryption_example_3"};
3564             bson_value_t datakey_id = {0};
3565             bson_value_t encrypted_field = {0};
3566             bson_value_t to_encrypt = {0};
3567             mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3568             bson_value_t decrypted = {0};
3569
3570             mongoc_init ();
3571
3572             /* Configure the master key. This must be the same master key that was used
3573              * to create the encryption key. */
3574             local_masterkey =
3575                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3576             if (!local_masterkey || local_masterkey_len != 96) {
3577                fprintf (stderr,
3578                         "Specify LOCAL_MASTERKEY environment variable as a "
3579                         "secure random 96 byte hex value.\n");
3580                goto fail;
3581             }
3582
3583             kms_providers = BCON_NEW ("local",
3584                                       "{",
3585                                       "key",
3586                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
3587                                       "}");
3588
3589             /* The mongoc_client_t used to read/write application data. */
3590             client =
3591                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3592             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3593
3594             /* Clear old data */
3595             mongoc_collection_drop (coll, NULL);
3596
3597             /* Set up the key vault for this example. */
3598             keyvault_coll =
3599                mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3600             mongoc_collection_drop (keyvault_coll, NULL);
3601
3602             /* Create a unique index to ensure that two data keys cannot share the same
3603              * keyAltName. This is recommended practice for the key vault. */
3604             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3605             index_opts = BCON_NEW ("unique",
3606                                    BCON_BOOL (true),
3607                                    "partialFilterExpression",
3608                                    "{",
3609                                    "keyAltNames",
3610                                    "{",
3611                                    "$exists",
3612                                    BCON_BOOL (true),
3613                                    "}",
3614                                    "}");
3615             index_model = mongoc_index_model_new (index_keys, index_opts);
3616             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
3617                                                               &index_model,
3618                                                               1,
3619                                                               NULL /* opts */,
3620                                                               NULL /* reply */,
3621                                                               &error);
3622
3623             if (!ret) {
3624                goto fail;
3625             }
3626
3627             client_encryption_opts = mongoc_client_encryption_opts_new ();
3628             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3629                                                              kms_providers);
3630             mongoc_client_encryption_opts_set_keyvault_namespace (
3631                client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3632
3633             /* Set a mongoc_client_t to use for reading/writing to the key vault. This
3634              * can be the same mongoc_client_t used by the main application. */
3635             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3636                                                                client);
3637             client_encryption =
3638                mongoc_client_encryption_new (client_encryption_opts, &error);
3639             if (!client_encryption) {
3640                goto fail;
3641             }
3642
3643             /* Create a new data key for the encryptedField.
3644              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3645              */
3646             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3647             mongoc_client_encryption_datakey_opts_set_keyaltnames (
3648                datakey_opts, keyaltnames, 1);
3649             if (!mongoc_client_encryption_create_datakey (
3650                    client_encryption, "local", datakey_opts, &datakey_id, &error)) {
3651                goto fail;
3652             }
3653
3654             /* Explicitly encrypt a field */
3655             encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
3656             mongoc_client_encryption_encrypt_opts_set_algorithm (
3657                encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
3658             mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id);
3659             to_encrypt.value_type = BSON_TYPE_UTF8;
3660             to_encrypt.value.v_utf8.str = "123456789";
3661             const size_t len = strlen (to_encrypt.value.v_utf8.str);
3662             BSON_ASSERT (bson_in_range_unsigned (uint32_t, len));
3663             to_encrypt.value.v_utf8.len = (uint32_t) len;
3664
3665             ret = mongoc_client_encryption_encrypt (
3666                client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
3667             if (!ret) {
3668                goto fail;
3669             }
3670
3671             to_insert = bson_new ();
3672             BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
3673             ret = mongoc_collection_insert_one (
3674                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3675             if (!ret) {
3676                goto fail;
3677             }
3678
3679             printf ("encrypted document: ");
3680             if (!print_one_document (coll, &error)) {
3681                goto fail;
3682             }
3683             printf ("\n");
3684
3685             /* Explicitly decrypt a field */
3686             ret = mongoc_client_encryption_decrypt (
3687                client_encryption, &encrypted_field, &decrypted, &error);
3688             if (!ret) {
3689                goto fail;
3690             }
3691             printf ("decrypted value: %s\n", decrypted.value.v_utf8.str);
3692
3693             exit_status = EXIT_SUCCESS;
3694          fail:
3695             if (error.code) {
3696                fprintf (stderr, "error: %s\n", error.message);
3697             }
3698
3699             bson_free (local_masterkey);
3700             bson_destroy (kms_providers);
3701             mongoc_collection_destroy (keyvault_coll);
3702             mongoc_index_model_destroy (index_model);
3703             bson_destroy (index_opts);
3704             bson_destroy (index_keys);
3705             mongoc_collection_destroy (coll);
3706             mongoc_client_destroy (client);
3707             bson_destroy (to_insert);
3708             bson_destroy (schema);
3709             bson_destroy (create_cmd);
3710             bson_destroy (create_cmd_opts);
3711             mongoc_write_concern_destroy (wc);
3712             mongoc_client_encryption_destroy (client_encryption);
3713             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3714             mongoc_client_encryption_opts_destroy (client_encryption_opts);
3715             bson_value_destroy (&encrypted_field);
3716             mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
3717             bson_value_destroy (&decrypted);
3718             bson_value_destroy (&datakey_id);
3719
3720             mongoc_cleanup ();
3721             return exit_status;
3722          }
3723
3724
3725   Explicit Encryption with Automatic Decryption
3726       Although automatic encryption requires MongoDB 4.2 enterprise or a Mon‐
3727       goDB 4.2 Atlas cluster,  automatic  decryption  is  supported  for  all
3728       users.  To  configure automatic decryption without automatic encryption
3729       set bypass_auto_encryption=True in mongoc_auto_encryption_opts_t:
3730
3731       client-side-encryption-auto-decryption.c
3732
3733          #include <mongoc/mongoc.h>
3734          #include <stdio.h>
3735          #include <stdlib.h>
3736
3737          #include "client-side-encryption-helpers.h"
3738
3739          /* This example demonstrates how to set up automatic decryption without
3740           * automatic encryption using the community version of MongoDB */
3741          int
3742          main (void)
3743          {
3744          /* The collection used to store the encryption data keys. */
3745          #define KEYVAULT_DB "encryption"
3746          #define KEYVAULT_COLL "__libmongocTestKeyVault"
3747          /* The collection used to store the encrypted documents in this example. */
3748          #define ENCRYPTED_DB "test"
3749          #define ENCRYPTED_COLL "coll"
3750
3751             int exit_status = EXIT_FAILURE;
3752             bool ret;
3753             uint8_t *local_masterkey = NULL;
3754             uint32_t local_masterkey_len;
3755             bson_t *kms_providers = NULL;
3756             bson_error_t error = {0};
3757             bson_t *index_keys = NULL;
3758             bson_t *index_opts = NULL;
3759             mongoc_index_model_t *index_model = NULL;
3760             bson_t *schema = NULL;
3761             mongoc_client_t *client = NULL;
3762             mongoc_collection_t *coll = NULL;
3763             mongoc_collection_t *keyvault_coll = NULL;
3764             bson_t *to_insert = NULL;
3765             bson_t *create_cmd = NULL;
3766             bson_t *create_cmd_opts = NULL;
3767             mongoc_write_concern_t *wc = NULL;
3768             mongoc_client_encryption_t *client_encryption = NULL;
3769             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
3770             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
3771             char *keyaltnames[] = {"mongoc_encryption_example_4"};
3772             bson_value_t datakey_id = {0};
3773             bson_value_t encrypted_field = {0};
3774             bson_value_t to_encrypt = {0};
3775             mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
3776             bson_value_t decrypted = {0};
3777             mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
3778             mongoc_client_t *unencrypted_client = NULL;
3779             mongoc_collection_t *unencrypted_coll = NULL;
3780
3781             mongoc_init ();
3782
3783             /* Configure the master key. This must be the same master key that was used
3784              * to create the encryption key. */
3785             local_masterkey =
3786                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
3787             if (!local_masterkey || local_masterkey_len != 96) {
3788                fprintf (stderr,
3789                         "Specify LOCAL_MASTERKEY environment variable as a "
3790                         "secure random 96 byte hex value.\n");
3791                goto fail;
3792             }
3793
3794             kms_providers = BCON_NEW ("local",
3795                                       "{",
3796                                       "key",
3797                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
3798                                       "}");
3799
3800             client =
3801                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3802             auto_encryption_opts = mongoc_auto_encryption_opts_new ();
3803             mongoc_auto_encryption_opts_set_keyvault_namespace (
3804                auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3805             mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
3806                                                            kms_providers);
3807
3808             /* Setting bypass_auto_encryption to true disables automatic encryption but
3809              * keeps the automatic decryption behavior. bypass_auto_encryption will also
3810              * disable spawning mongocryptd */
3811             mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts,
3812                                                                     true);
3813
3814             /* Once bypass_auto_encryption is set, community users can enable auto
3815              * encryption on the client. This will, in fact, only perform automatic
3816              * decryption. */
3817             ret = mongoc_client_enable_auto_encryption (
3818                client, auto_encryption_opts, &error);
3819             if (!ret) {
3820                goto fail;
3821             }
3822
3823             /* Now that automatic decryption is on, we can test it by inserting a
3824              * document with an explicitly encrypted value into the collection. When we
3825              * look up the document later, it should be automatically decrypted for us.
3826              */
3827             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);
3828
3829             /* Clear old data */
3830             mongoc_collection_drop (coll, NULL);
3831
3832             /* Set up the key vault for this example. */
3833             keyvault_coll =
3834                mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
3835             mongoc_collection_drop (keyvault_coll, NULL);
3836
3837             /* Create a unique index to ensure that two data keys cannot share the same
3838              * keyAltName. This is recommended practice for the key vault. */
3839             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
3840             index_opts = BCON_NEW ("unique",
3841                                    BCON_BOOL (true),
3842                                    "partialFilterExpression",
3843                                    "{",
3844                                    "keyAltNames",
3845                                    "{",
3846                                    "$exists",
3847                                    BCON_BOOL (true),
3848                                    "}",
3849                                    "}");
3850             index_model = mongoc_index_model_new (index_keys, index_opts);
3851             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
3852                                                               &index_model,
3853                                                               1,
3854                                                               NULL /* opts */,
3855                                                               NULL /* reply */,
3856                                                               &error);
3857
3858             if (!ret) {
3859                goto fail;
3860             }
3861
3862             client_encryption_opts = mongoc_client_encryption_opts_new ();
3863             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
3864                                                              kms_providers);
3865             mongoc_client_encryption_opts_set_keyvault_namespace (
3866                client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
3867
3868             /* The key vault client is used for reading to/from the key vault. This can
3869              * be the same mongoc_client_t used by the application. */
3870             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
3871                                                                client);
3872             client_encryption =
3873                mongoc_client_encryption_new (client_encryption_opts, &error);
3874             if (!client_encryption) {
3875                goto fail;
3876             }
3877
3878             /* Create a new data key for the encryptedField.
3879              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
3880              */
3881             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
3882             mongoc_client_encryption_datakey_opts_set_keyaltnames (
3883                datakey_opts, keyaltnames, 1);
3884             ret = mongoc_client_encryption_create_datakey (
3885                client_encryption, "local", datakey_opts, &datakey_id, &error);
3886             if (!ret) {
3887                goto fail;
3888             }
3889
3890             /* Explicitly encrypt a field. */
3891             encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
3892             mongoc_client_encryption_encrypt_opts_set_algorithm (
3893                encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
3894             mongoc_client_encryption_encrypt_opts_set_keyaltname (
3895                encrypt_opts, "mongoc_encryption_example_4");
3896             to_encrypt.value_type = BSON_TYPE_UTF8;
3897             to_encrypt.value.v_utf8.str = "123456789";
3898             const size_t len = strlen (to_encrypt.value.v_utf8.str);
3899             BSON_ASSERT (bson_in_range_unsigned (uint32_t, len));
3900             to_encrypt.value.v_utf8.len = (uint32_t) len;
3901
3902             ret = mongoc_client_encryption_encrypt (
3903                client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
3904             if (!ret) {
3905                goto fail;
3906             }
3907
3908             to_insert = bson_new ();
3909             BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
3910             ret = mongoc_collection_insert_one (
3911                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
3912             if (!ret) {
3913                goto fail;
3914             }
3915
3916             /* When we retrieve the document, any encrypted fields will get automatically
3917              * decrypted by the driver. */
3918             printf ("decrypted document: ");
3919             if (!print_one_document (coll, &error)) {
3920                goto fail;
3921             }
3922             printf ("\n");
3923
3924             unencrypted_client =
3925                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
3926             unencrypted_coll = mongoc_client_get_collection (
3927                unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
3928
3929             printf ("encrypted document: ");
3930             if (!print_one_document (unencrypted_coll, &error)) {
3931                goto fail;
3932             }
3933             printf ("\n");
3934
3935             exit_status = EXIT_SUCCESS;
3936          fail:
3937             if (error.code) {
3938                fprintf (stderr, "error: %s\n", error.message);
3939             }
3940
3941             bson_free (local_masterkey);
3942             bson_destroy (kms_providers);
3943             mongoc_collection_destroy (keyvault_coll);
3944             mongoc_index_model_destroy (index_model);
3945             bson_destroy (index_opts);
3946             bson_destroy (index_keys);
3947             mongoc_collection_destroy (coll);
3948             mongoc_client_destroy (client);
3949             bson_destroy (to_insert);
3950             bson_destroy (schema);
3951             bson_destroy (create_cmd);
3952             bson_destroy (create_cmd_opts);
3953             mongoc_write_concern_destroy (wc);
3954             mongoc_client_encryption_destroy (client_encryption);
3955             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
3956             mongoc_client_encryption_opts_destroy (client_encryption_opts);
3957             bson_value_destroy (&encrypted_field);
3958             mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
3959             bson_value_destroy (&decrypted);
3960             bson_value_destroy (&datakey_id);
3961             mongoc_collection_destroy (unencrypted_coll);
3962             mongoc_client_destroy (unencrypted_client);
3963             mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
3964
3965             mongoc_cleanup ();
3966             return exit_status;
3967          }
3968
3969
3970   Queryable Encryption
3971       Using Queryable Encryption requires MongoDB Server 7.0 or higher.
3972
3973       See the MongoDB Manual for Queryable Encryption  for  more  information
3974       about the feature.
3975
3976       API  related  to the "rangePreview" algorithm is still experimental and
3977       subject to breaking changes!
3978
3979   Queryable Encryption in older MongoDB Server versions
3980       MongoDB Server 6.0 introduced Queryable Encryption as a Public  Techni‐
3981       cal  Preview. MongoDB Server 7.0 includes backwards breaking changes to
3982       the Queryable Encryption protocol.
3983
3984       The backwards breaking changes are applied in the  client  protocol  in
3985       libmongocrypt  1.8.0.  libmongoc 1.24.0 requires libmongocrypt 1.8.0 or
3986       newer.  libmongoc 1.24.0 no longer  supports  Queryable  Encryption  in
3987       MongoDB  Server  <7.0.  Using Queryable Encryption libmongoc 1.24.0 and
3988       higher requires MongoDB Server >=7.0.
3989
3990       Using  Queryable  Encryption  with  libmongocrypt<1.8.0  on  a  MongoDB
3991       Server>=7.0, or using libmongocrypt>=1.8.0 on a MongoDB Server<6.0 will
3992       result in a server error when using the incompatible protocol.
3993
3994       SEE ALSO:
3995          The MongoDB Manual for Queryable Encryption
3996
3997
3998   Installation
3999       Using In-Use Encryption in the C driver requires the dependency libmon‐
4000       gocrypt. See the MongoDB Manual for libmongocrypt installation instruc‐
4001       tions.
4002
4003       Once libmongocrypt is installed, configure  the  C  driver  with  -DEN‐
4004       ABLE_CLIENT_SIDE_ENCRYPTION=ON to require In-Use Encryption be enabled.
4005
4006          $ cd mongo-c-driver
4007          $ mkdir cmake-build && cd cmake-build
4008          $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_CLIENT_SIDE_ENCRYPTION=ON ..
4009          $ cmake --build . --target install
4010
4011   API
4012       mongoc_client_encryption_t is used for explicit encryption and key man‐
4013       agement.           mongoc_client_enable_auto_encryption()           and
4014       mongoc_client_pool_enable_auto_encryption() is used to enable automatic
4015       encryption.
4016
4017       The Queryable Encryption and CSFLE features share much of the same  API
4018       with some exceptions.
4019
4020       • The         supported         algorithms         documented        in
4021         mongoc_client_encryption_encrypt_opts_set_algorithm() do not apply to
4022         both features.
4023
4024mongoc_auto_encryption_opts_set_encrypted_fields_map()  only  applies
4025         to Queryable Encryption.
4026
4027mongoc_auto_encryption_opts_set_schema_map() only applies to CSFLE.
4028
4029   Query Analysis
4030       To support the automatic encryption feature, one of the  following  de‐
4031       pendencies are required:
4032
4033       • The  mongocryptd  executable.  See  the MongoDB Manual documentation:
4034         Install and Configure mongocryptd
4035
4036       • The crypt_shared  library.  See  the  MongoDB  Manual  documentation:
4037         Automatic Encryption Shared Library
4038
4039       A  mongoc_client_t or mongoc_client_pool_t configured with auto encryp‐
4040       tion will automatically try to load the crypt_shared library. If  load‐
4041       ing   the   crypt_shared   library   fails,   the   mongoc_client_t  or
4042       mongoc_client_pool_t will try to spawn the mongocryptd process from the
4043       application's  PATH.  To  configure use of crypt_shared and mongocryptd
4044       see mongoc_auto_encryption_opts_set_extra().
4045

AUTHOR

4047       MongoDB, Inc
4048
4050       2017-present, MongoDB, Inc
4051
4052
4053
4054
40551.24.3                           Aug 17, 2023                 MONGOC_GUIDES(3)
Impressum