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

CREATING INDEXES

2739       To create indexes on a MongoDB collection,  execute  the  createIndexes
2740       command        with        a        command        function        like
2741       mongoc_database_write_command_with_opts()                            or
2742       mongoc_collection_write_command_with_opts(). See the MongoDB Manual en‐
2743       try for the createIndexes command for details.
2744
2745       WARNING:
2746          The commitQuorum option to the createIndexes command  is  only  sup‐
2747          ported  in MongoDB 4.4+ servers, but it is not validated in the com‐
2748          mand functions. Do not pass commitQuorum if connected to server ver‐
2749          sions  less  than  4.4. Using the commitQuorum option on server ver‐
2750          sions less than 4.4 may have adverse effects on index builds.
2751
2752   Example
2753       example-create-indexes.c
2754
2755          /* gcc example-create-indexes.c -o example-create-indexes $(pkg-config --cflags
2756           * --libs libmongoc-1.0) */
2757
2758          /* ./example-create-indexes [CONNECTION_STRING [COLLECTION_NAME]] */
2759
2760          #include <mongoc/mongoc.h>
2761          #include <stdio.h>
2762          #include <stdlib.h>
2763
2764          int
2765          main (int argc, char *argv[])
2766          {
2767             mongoc_client_t *client;
2768             const char *uri_string =
2769                "mongodb://127.0.0.1/?appname=create-indexes-example";
2770             mongoc_uri_t *uri;
2771             mongoc_database_t *db;
2772             const char *collection_name = "test";
2773             bson_t keys;
2774             char *index_name;
2775             bson_t *create_indexes;
2776             bson_t reply;
2777             char *reply_str;
2778             bson_error_t error;
2779             bool r;
2780
2781             mongoc_init ();
2782
2783             if (argc > 1) {
2784                uri_string = argv[1];
2785             }
2786
2787             if (argc > 2) {
2788                collection_name = argv[2];
2789             }
2790
2791             uri = mongoc_uri_new_with_error (uri_string, &error);
2792             if (!uri) {
2793                fprintf (stderr,
2794                         "failed to parse URI: %s\n"
2795                         "error message:       %s\n",
2796                         uri_string,
2797                         error.message);
2798                return EXIT_FAILURE;
2799             }
2800
2801             client = mongoc_client_new_from_uri (uri);
2802             if (!client) {
2803                return EXIT_FAILURE;
2804             }
2805
2806             mongoc_client_set_error_api (client, 2);
2807             db = mongoc_client_get_database (client, "test");
2808
2809             /* ascending index on field "x" */
2810             bson_init (&keys);
2811             BSON_APPEND_INT32 (&keys, "x", 1);
2812             index_name = mongoc_collection_keys_to_index_string (&keys);
2813             create_indexes = BCON_NEW ("createIndexes",
2814                                        BCON_UTF8 (collection_name),
2815                                        "indexes",
2816                                        "[",
2817                                        "{",
2818                                        "key",
2819                                        BCON_DOCUMENT (&keys),
2820                                        "name",
2821                                        BCON_UTF8 (index_name),
2822                                        "}",
2823                                        "]");
2824
2825             r = mongoc_database_write_command_with_opts (
2826                db, create_indexes, NULL /* opts */, &reply, &error);
2827
2828             reply_str = bson_as_json (&reply, NULL);
2829             printf ("%s\n", reply_str);
2830
2831             if (!r) {
2832                fprintf (stderr, "Error in createIndexes: %s\n", error.message);
2833             }
2834
2835             bson_free (index_name);
2836             bson_free (reply_str);
2837             bson_destroy (&reply);
2838             bson_destroy (create_indexes);
2839             mongoc_database_destroy (db);
2840             mongoc_uri_destroy (uri);
2841             mongoc_client_destroy (client);
2842
2843             mongoc_cleanup ();
2844
2845             return r ? EXIT_SUCCESS : EXIT_FAILURE;
2846          }
2847
2848

AIDS FOR DEBUGGING

2850   GDB
2851       This repository contains a .gdbinit file that contains helper functions
2852       to   aid  debugging  of  data  structures.  GDB  will  load  this  file
2853       automatically if you  have  added  the  directory  which  contains  the
2854       .gdbinit  file to GDB's auto-load safe-path, and you start GDB from the
2855       directory which holds the .gdbinit file.
2856
2857       You can see the safe-path  with  show  auto-load  safe-path  on  a  GDB
2858       prompt. You can configure it by setting it in ~/.gdbinit with:
2859
2860          add-auto-load-safe-path /path/to/mongo-c-driver
2861
2862       If you haven't added the path to your auto-load safe-path, or start GDB
2863       in another directory, load the file with:
2864
2865          source path/to/mongo-c-driver/.gdbinit
2866
2867       The .gdbinit file defines the printbson function, which shows the  con‐
2868       tents  of  a  bson_t  * variable.  If you have a local bson_t, then you
2869       must prefix the variable with a &.
2870
2871       An example GDB session looks like:
2872
2873          (gdb) printbson bson
2874          ALLOC [0x555556cd7310 + 0] (len=475)
2875          {
2876              'bool' : true,
2877              'int32' : NumberInt("42"),
2878              'int64' : NumberLong("3000000042"),
2879              'string' : "Stŕìñg",
2880              'objectId' : ObjectID("5A1442F3122D331C3C6757E1"),
2881              'utcDateTime' : UTCDateTime(1511277299031),
2882              'arrayOfInts' : [
2883                  '0' : NumberInt("1"),
2884                  '1' : NumberInt("2")
2885              ],
2886              'embeddedDocument' : {
2887                  'arrayOfStrings' : [
2888                      '0' : "one",
2889                      '1' : "two"
2890                  ],
2891                  'double' : 2.718280,
2892                  'notherDoc' : {
2893                      'true' : NumberInt("1"),
2894                      'false' : false
2895                  }
2896              },
2897              'binary' : Binary("02", "3031343532333637"),
2898              'regex' : Regex("@[a-z]+@", "im"),
2899              'null' : null,
2900              'js' : JavaScript("print foo"),
2901              'jsws' : JavaScript("print foo") with scope: {
2902                  'f' : NumberInt("42"),
2903                  'a' : [
2904                      '0' : 3.141593,
2905                      '1' : 2.718282
2906                  ]
2907              },
2908              'timestamp' : Timestamp(4294967295, 4294967295),
2909              'double' : 3.141593
2910          }
2911
2912   LLDB
2913       This repository also includes a script that customizes LLDB's  standard
2914       print command to print a bson_t or bson_t * as JSON:
2915
2916          (lldb) print b
2917          (bson_t) $0 = {"x": 1, "y": 2}
2918
2919       The custom bson command provides more options:
2920
2921          (lldb) bson --verbose b
2922          len=19
2923          flags=INLINE|STATIC
2924          {
2925            "x": 1,
2926            "y": 2
2927          }
2928          (lldb) bson --raw b
2929          '\x13\x00\x00\x00\x10x\x00\x01\x00\x00\x00\x10y\x00\x02\x00\x00\x00\x00'
2930
2931       Type help bson for a list of options.
2932
2933       The  script  requires a build of libbson with debug symbols, and an in‐
2934       stallation of PyMongo. Install PyMongo with:
2935
2936          python -m pip install pymongo
2937
2938       If you see "No module named pip" then you must install  pip,  then  run
2939       the previous command again.
2940
2941       Create a file ~/.lldbinit containing:
2942
2943          command script import /path/to/mongo-c-driver/lldb_bson.py
2944
2945       If  you  see  "bson command installed by lldb_bson" at the beginning of
2946       your LLDB session, you've installed the script correctly.
2947
2948   Debug assertions
2949       To enable runtime debug assertions, configure  with  -DENABLE_DEBUG_AS‐
2950       SERTIONS=ON.
2951

USING CLIENT-SIDE FIELD LEVEL ENCRYPTION

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

AUTHOR

4155       MongoDB, Inc
4156
4158       2017-present, MongoDB, Inc
4159
4160
4161
4162
41631.23.1                           Oct 20, 2022                 MONGOC_GUIDES(3)
Impressum