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 the URI.
11
12          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
13          mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
14
15          mongoc_client_t *client = mongoc_client_new_from_uri (uri);
16
17       The following URI options may be used to further configure TLS:
18
19          ┌────────────────────┬─────────────────────┬─────────────────────┐
20          │Constant            │ Key                 │ Description         │
21          ├────────────────────┼─────────────────────┼─────────────────────┤
22          │MONGOC_URI_TLS      │ tls                 │ {true|false}, indi‐ │
23          │                    │                     │ cating if TLS  must │
24          │                    │                     │ be used.            │
25          ├────────────────────┼─────────────────────┼─────────────────────┤
26          │MONGOC_URI_TLSCER‐  │ tlscertificatekey‐  │ Path to PEM format‐ │
27          │TIFICATEKEYFILE     │ file                │ ted  Private   Key, │
28          │                    │                     │ with   its   Public │
29          │                    │                     │ Certificate    con‐ │
30          │                    │                     │ catenated   at  the │
31          │                    │                     │ end.                │
32          ├────────────────────┼─────────────────────┼─────────────────────┤
33          │MONGOC_URI_TLSCER‐  │ tlscertificatekey‐  │ The  password,   if │
34          │TIFICATEKEYPASSWORD │ password            │ any,  to use to un‐ │
35          │                    │                     │ 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 Tu‐
590       torial. To establish a connection with authentication options  enabled,
591       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 launches
830       monitoring  threads in the background. Monitoring threads independently
831       connect to all servers in the connection string. As monitoring  threads
832       receive  ismaster  responses  from  the servers, they update the shared
833       view of the server topology. Additional monitoring threads and  connec‐
834       tions are created as new servers are discovered. Monitoring threads are
835       terminated when servers are removed from the shared view of the  server
836       topology.
837
838       Each  thread  that  executes MongoDB operations must check out a client
839       from the pool:
840
841          mongoc_client_t *client = mongoc_client_pool_pop (pool);
842
843          /* use the client for operations ... */
844
845          mongoc_client_pool_push (pool, client);
846
847       The  mongoc_client_t  object  is  not  thread-safe,   only   the   mon‐
848       goc_client_pool_t is.
849
850       When  the  driver  is in pooled mode, your program's operations are 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  pool.
864       (See  mongoc_uri_t.)   If  waitQueueTimeoutMS  is specified, then it is
865       necessary to confirm that a client was actually returned:
866
867          mongoc_uri_t *uri = mongoc_uri_new (
868             "mongodb://hostA,hostB/?replicaSet=my_rs&waitQueueTimeoutMS=1000");
869
870          mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);
871
872          mongoc_client_t *client = mongoc_client_pool_pop (pool);
873
874          if (client) {
875             /* use the client for operations ... */
876
877             mongoc_client_pool_push (pool, client);
878          } else {
879             /* take appropriate action for a timeout */
880          }
881
882       See connection_pool_options to configure pool size  and  behavior,  and
883       see  mongoc_client_pool_t  for  an extended example of a multi-threaded
884       program that uses the driver in pooled mode.
885

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 mongoc_cursor_set_max_await_time_ms.
1102

BULK WRITE OPERATIONS

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

AGGREGATION FRAMEWORK EXAMPLES

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

DISTINCT AND MAPREDUCE

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

USING LIBMONGOC IN A MICROSOFT VISUAL STUDIO PROJECT

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

CREATING INDEXES

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

AIDS FOR DEBUGGING

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

USING CLIENT-SIDE FIELD LEVEL ENCRYPTION

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

AUTHOR

4138       MongoDB, Inc
4139
4141       2017-present, MongoDB, Inc
4142
4143
4144
4145
41461.17.6                           Jun 03, 2021                 MONGOC_GUIDES(3)
Impressum