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 │
35          │                    │                     │ unlock    encrypted │
36          │                    │                     │ Private Key.        │
37          ├────────────────────┼─────────────────────┼─────────────────────┤
38          │MON‐                │ tlscafile           │ One,  or  a  bundle │
39          │GOC_URI_TLSCAFILE   │                     │ of,     Certificate │
40          │                    │                     │ Authorities    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 │
56          │                    │                     │ issued  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            MON‐ │
75          │                    │                     │ GOC_URI_TLSALLOWIN‐ │
76          │                    │                     │ VALIDHOSTNAMES.     │
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 │
86          │POINTCHECK          │                     │ responder endpoints │
87          │                    │                     │ should    not    be │
88          │                    │                     │ requested  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
122       authority  specified  by  --tlsCAFile,  or  an authority trusted by the
123       native 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
151       potentially  revoked  certificates (when tlsDisableOCSPEndpointCheck or
152       tlsDisableCertificateRevocationCheck are set).
153
154   Supported Libraries
155       By default, libmongoc will attempt to find a supported TLS library  and
156       enable  TLS  support.  This is controlled by the cmake flag ENABLE_SSL,
157       which is set to AUTO by default. Valid values are:
158
159       · AUTO the default behavior. Link to the system's native  TLS  library,
160         or attempt to find OpenSSL.
161
162       · DARWIN link to Secure Transport, the native TLS library on macOS.
163
164       · WINDOWS link to Secure Channel, the native TLS library on Windows.
165
166       · OPENSSL  link  to  OpenSSL  (libssl). An optional install path may be
167         specified with OPENSSL_ROOT.
168
169       · LIBRESSL link to LibreSSL's libtls. (LibreSSL's compatible libssl may
170         be linked to by setting OPENSSL).
171
172       · OFF disable TLS support.
173
174   OpenSSL
175       The  MongoDB  C  Driver  uses  OpenSSL, if available, on Linux and Unix
176       platforms (besides macOS). Industry best practices and some regulations
177       require  the  use  of TLS 1.1 or newer, which requires at least OpenSSL
178       1.0.1. Check your OpenSSL version like so:
179
180          $ openssl version
181
182       Ensure your system's OpenSSL is a recent version (at least  1.0.1),  or
183       install  a  recent  version  in  a non-system path and build against it
184       with:
185
186          cmake -DOPENSSL_ROOT_DIR=/absolute/path/to/openssl
187
188       When compiled against OpenSSL, the driver will attempt to load the sys‐
189       tem  default certificate store, as configured by the distribution. That
190       can be overridden by setting the  tlsCAFile  URI  option  or  with  the
191       fields ca_file and ca_dir in the mongoc_ssl_opt_t.
192
193       The  Online  Certificate Status Protocol (OCSP) (see RFC 6960) is fully
194       supported when using OpenSSL 1.0.1+ with the following notes:
195
196       · When a crl_file  is  set  with  mongoc_ssl_opt_t,  and  the  crl_file
197         revokes  the  server's  certificate,  the  certificate  is considered
198         revoked (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
204       libressl.
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
256         revokes 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.)
266       native  TLS  library  (Secure Transport), and its native crypto library
267       (Common Crypto, or CC).
268
269       When compiled against Secure Transport, the ca_dir and crl_file options
270       of  a  mongoc_ssl_opt_t are not supported. An error is issued if either
271       are used.
272
273       When tlsCAFile is set, the driver will only allow  server  certificates
274       issued by the authority (or authorities) provided. When no tlsCAFile is
275       set, the driver will use the Certificate Authorities in  the  currently
276       unlocked keychains.
277
278       Setting  tlsDisableOCSPEndpointCheck  and  tlsDisableCertificateRevoca‐
279       tionCheck has no effect.
280
281       The Online Certificate Status Protocol (OCSP) (see RFC  6960)  is  par‐
282       tially supported with the following notes.
283
284       · The  Must-Staple  extension (see RFC 7633) is ignored. Connection may
285         continue if a Must-Staple certificate is presented  with  no  stapled
286         response  (unless the client receives a revoked response from an OCSP
287         responder).
288
289       · Connection will continue if a Must-Staple  certificate  is  presented
290         without a stapled response and the OCSP responder is down.
291

COMMON TASKS

293       Drivers  for  some  other languages provide helper functions to perform
294       certain common tasks. In the C Driver we must explicitly build commands
295       to send to the server.
296
297   Setup
298       First we'll write some code to insert sample data:
299
300       doc-common-insert.c
301
302          /* Don't try to compile this file on its own. It's meant to be #included
303             by example code */
304
305          /* Insert some sample data */
306          bool
307          insert_data (mongoc_collection_t *collection)
308          {
309             mongoc_bulk_operation_t *bulk;
310             enum N { ndocs = 4 };
311             bson_t *docs[ndocs];
312             bson_error_t error;
313             int i = 0;
314             bool ret;
315
316             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
317
318             docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
319             docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
320             docs[2] = BCON_NEW (
321                "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
322             docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
323
324             for (i = 0; i < ndocs; i++) {
325                mongoc_bulk_operation_insert (bulk, docs[i]);
326                bson_destroy (docs[i]);
327                docs[i] = NULL;
328             }
329
330             ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
331
332             if (!ret) {
333                fprintf (stderr, "Error inserting data: %s\n", error.message);
334             }
335
336             mongoc_bulk_operation_destroy (bulk);
337             return ret;
338          }
339
340          /* A helper which we'll use a lot later on */
341          void
342          print_res (const bson_t *reply)
343          {
344             char *str;
345             BSON_ASSERT (reply);
346             str = bson_as_canonical_extended_json (reply, NULL);
347             printf ("%s\n", str);
348             bson_free (str);
349          }
350
351
352   explain Command
353       This is how to use the explain command in MongoDB 3.2+:
354
355       explain.c
356
357          bool
358          explain (mongoc_collection_t *collection)
359          {
360             bson_t *command;
361             bson_t reply;
362             bson_error_t error;
363             bool res;
364
365             command = BCON_NEW ("explain",
366                                 "{",
367                                 "find",
368                                 BCON_UTF8 (COLLECTION_NAME),
369                                 "filter",
370                                 "{",
371                                 "x",
372                                 BCON_INT32 (1),
373                                 "}",
374                                 "}");
375             res = mongoc_collection_command_simple (
376                collection, command, NULL, &reply, &error);
377             if (!res) {
378                fprintf (stderr, "Error with explain: %s\n", error.message);
379                goto cleanup;
380             }
381
382             /* Do something with the reply */
383             print_res (&reply);
384
385          cleanup:
386             bson_destroy (&reply);
387             bson_destroy (command);
388             return res;
389          }
390
391
392   Running the Examples
393       common-operations.c
394
395          /*
396           * Copyright 2016 MongoDB, Inc.
397           *
398           * Licensed under the Apache License, Version 2.0 (the "License");
399           * you may not use this file except in compliance with the License.
400           * You may obtain a copy of the License at
401           *
402           *   http://www.apache.org/licenses/LICENSE-2.0
403           *
404           * Unless required by applicable law or agreed to in writing, software
405           * distributed under the License is distributed on an "AS IS" BASIS,
406           * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
407           * See the License for the specific language governing permissions and
408           * limitations under the License.
409           */
410
411
412          #include <mongoc/mongoc.h>
413          #include <stdio.h>
414
415
416          const char *COLLECTION_NAME = "things";
417
418          #include "../doc-common-insert.c"
419          #include "explain.c"
420
421
422          int
423          main (int argc, char *argv[])
424          {
425             mongoc_database_t *database = NULL;
426             mongoc_client_t *client = NULL;
427             mongoc_collection_t *collection = NULL;
428             mongoc_uri_t *uri = NULL;
429             bson_error_t error;
430             char *host_and_port;
431             int res = 0;
432
433             if (argc < 2 || argc > 3) {
434                fprintf (stderr,
435                         "usage: %s MONGOD-1-CONNECTION-STRING "
436                         "[MONGOD-2-HOST-NAME:MONGOD-2-PORT]\n",
437                         argv[0]);
438                fprintf (stderr,
439                         "MONGOD-1-CONNECTION-STRING can be "
440                         "of the following forms:\n");
441                fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
442                fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
443                fprintf (stderr,
444                         "mongodb://user:pass@localhost:27017\t"
445                         "local machine on port 27017, and authenticate with username "
446                         "user and password pass\n");
447                return EXIT_FAILURE;
448             }
449
450             mongoc_init ();
451
452             if (strncmp (argv[1], "mongodb://", 10) == 0) {
453                host_and_port = bson_strdup (argv[1]);
454             } else {
455                host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
456             }
457
458             uri = mongoc_uri_new_with_error (host_and_port, &error);
459             if (!uri) {
460                fprintf (stderr,
461                         "failed to parse URI: %s\n"
462                         "error message:       %s\n",
463                         host_and_port,
464                         error.message);
465                res = EXIT_FAILURE;
466                goto cleanup;
467             }
468
469             client = mongoc_client_new_from_uri (uri);
470             if (!client) {
471                res = EXIT_FAILURE;
472                goto cleanup;
473             }
474
475             mongoc_client_set_error_api (client, 2);
476             database = mongoc_client_get_database (client, "test");
477             collection = mongoc_database_get_collection (database, COLLECTION_NAME);
478
479             printf ("Inserting data\n");
480             if (!insert_data (collection)) {
481                res = EXIT_FAILURE;
482                goto cleanup;
483             }
484
485             printf ("explain\n");
486             if (!explain (collection)) {
487                res = EXIT_FAILURE;
488                goto cleanup;
489             }
490
491          cleanup:
492             if (collection) {
493                mongoc_collection_destroy (collection);
494             }
495
496             if (database) {
497                mongoc_database_destroy (database);
498             }
499
500             if (client) {
501                mongoc_client_destroy (client);
502             }
503
504             if (uri) {
505                mongoc_uri_destroy (uri);
506             }
507
508             bson_free (host_and_port);
509             mongoc_cleanup ();
510             return res;
511          }
512
513
514       First  launch two separate instances of mongod (must be done from sepa‐
515       rate shells):
516
517          $ mongod
518
519          $ mkdir /tmp/db2
520          $ mongod --dbpath /tmp/db2 --port 27018 # second instance
521
522       Now compile and run the example program:
523
524          $ cd examples/common_operations/$ gcc -Wall -o example common-operations.c $(pkg-config --cflags --libs libmongoc-1.0)$ ./example localhost:27017 localhost:27018
525          Inserting data
526          explain
527          {
528             "executionStats" : {
529                "allPlansExecution" : [],
530                "executionStages" : {
531                   "advanced" : 19,
532                   "direction" : "forward" ,
533                   "docsExamined" : 76,
534                   "executionTimeMillisEstimate" : 0,
535                   "filter" : {
536                      "x" : {
537                         "$eq" : 1
538                      }
539                   },
540                   "invalidates" : 0,
541                   "isEOF" : 1,
542                   "nReturned" : 19,
543                   "needTime" : 58,
544                   "needYield" : 0,
545                   "restoreState" : 0,
546                   "saveState" : 0,
547                   "stage" : "COLLSCAN" ,
548                   "works" : 78
549                },
550                "executionSuccess" : true,
551                "executionTimeMillis" : 0,
552                "nReturned" : 19,
553                "totalDocsExamined" : 76,
554                "totalKeysExamined" : 0
555             },
556             "ok" : 1,
557             "queryPlanner" : {
558                "indexFilterSet" : false,
559                "namespace" : "test.things",
560                "parsedQuery" : {
561                   "x" : {
562                      "$eq" : 1
563                   }
564                },
565                "plannerVersion" : 1,
566                "rejectedPlans" : [],
567                "winningPlan" : {
568                   "direction" : "forward" ,
569                   "filter" : {
570                      "x" : {
571                         "$eq" : 1
572                      }
573                   },
574                   "stage" : "COLLSCAN"
575                }
576             },
577             "serverInfo" : {
578                "gitVersion" : "05552b562c7a0b3143a729aaa0838e558dc49b25" ,
579                "host" : "MacBook-Pro-57.local",
580                "port" : 27017,
581                "version" : "3.2.6"
582             }
583          }
584

ADVANCED CONNECTIONS

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

BULK WRITE OPERATIONS

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

AGGREGATION FRAMEWORK EXAMPLES

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

DISTINCT AND MAPREDUCE

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

USING LIBMONGOC IN A MICROSOFT VISUAL STUDIO PROJECT

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

CREATING INDEXES

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

AIDS FOR DEBUGGING

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

USING CLIENT-SIDE FIELD LEVEL ENCRYPTION

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

AUTHOR

4139       MongoDB, Inc
4140
4142       2017-present, MongoDB, Inc
4143
4144
4145
4146
41471.17.4                           Feb 04, 2021                 MONGOC_GUIDES(3)
Impressum