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

NAME

6       mongoc_guides - Guides
7

CONFIGURING TLS

9   Configuration with URI options
10       Enable TLS by including tls=true in the URI.
11
12          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
13          mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
14
15          mongoc_client_t *client = mongoc_client_new_from_uri (uri);
16
17       The following URI options may be used to further configure TLS:
18
19          ┌────────────────────┬─────────────────────┬─────────────────────┐
20          │Constant            │ Key                 │ Description         │
21          ├────────────────────┼─────────────────────┼─────────────────────┤
22          │MONGOC_URI_TLS      │ tls                 │ {true|false}, indi‐ │
23          │                    │                     │ cating if TLS  must │
24          │                    │                     │ be used.            │
25          ├────────────────────┼─────────────────────┼─────────────────────┤
26          │MONGOC_URI_TLSCER‐  │ tlscertificatekey‐  │ Path to PEM format‐ │
27          │TIFICATEKEYFILE     │ file                │ ted  Private   Key, │
28          │                    │                     │ with   its   Public │
29          │                    │                     │ Certificate    con‐ │
30          │                    │                     │ catenated   at  the │
31          │                    │                     │ end.                │
32          ├────────────────────┼─────────────────────┼─────────────────────┤
33          │MONGOC_URI_TLSCER‐  │ tlscertificatekey‐  │ The   password,  if │
34          │TIFICATEKEY‐        │ password            │ any, to use to  un‐ │
35          │FILEPASSWORD        │                     │ lock encrypted Pri‐ │
36          │                    │                     │ vate Key.           │
37          ├────────────────────┼─────────────────────┼─────────────────────┤
38          │MON‐                │ tlscafile           │ One,  or  a  bundle │
39          │GOC_URI_TLSCAFILE   │                     │ of, Certificate Au‐ │
40          │                    │                     │ thorities      whom │
41          │                    │                     │ should  be  consid‐ │
42          │                    │                     │ ered to be trusted. │
43          ├────────────────────┼─────────────────────┼─────────────────────┤
44          │MONGOC_URI_TLSAL‐   │ tlsallowinvalidcer‐ │ Accept  and  ignore │
45          │LOWINVALIDCERTIFI‐  │ tificates           │ certificate verifi‐ │
46          │CATES               │                     │ cation errors (e.g. │
47          │                    │                     │ untrusted   issuer, │
48          │                    │                     │ expired, etc.)      │
49          ├────────────────────┼─────────────────────┼─────────────────────┤
50          │MONGOC_URI_TLSAL‐   │ tlsallowinvalid‐    │ Ignore     hostname │
51          │LOWINVALIDHOSTNAMES │ hostnames           │ verification of the │
52          │                    │                     │ certificate   (e.g. │
53          │                    │                     │ Man  In The Middle, │
54          │                    │                     │ using  valid   cer‐ │
55          │                    │                     │ tificate,  but  is‐ │
56          │                    │                     │ sued  for   another │
57          │                    │                     │ hostname)           │
58          └────────────────────┴─────────────────────┴─────────────────────┘
59
60
61
62
63
64
65
66
67          │MONGOC_URI_TLSINSE‐ │ tlsinsecure         │ {true|false}, indi‐ │
68          │CURE                │                     │ cating  if insecure │
69          │                    │                     │ TLS options  should │
70          │                    │                     │ be  used. Currently │
71          │                    │                     │ this  implies  MON‐ │
72          │                    │                     │ GOC_URI_TLSALLOWIN‐ │
73          │                    │                     │ VALIDCERTIFICATES   │
74          │                    │                     │ and  MONGOC_URI_TL‐ │
75          │                    │                     │ SALLOWINVALIDHOST‐  │
76          │                    │                     │ NAMES.              │
77          ├────────────────────┼─────────────────────┼─────────────────────┤
78          │MONGOC_URI_TLSDIS‐  │ tlsdisablecertifi‐  │ {true|false}, indi‐ │
79          │ABLECERTIFICATERE‐  │ caterevocationcheck │ cates if revocation │
80          │VOCATIONCHECK       │                     │ checking   (CRL   / │
81          │                    │                     │ OCSP)   should   be │
82          │                    │                     │ disabled.           │
83          ├────────────────────┼─────────────────────┼─────────────────────┤
84          │MONGOC_URI_TLSDIS‐  │ tlsdisableocspend‐  │ {true|false}, indi‐ │
85          │ABLEOCSPEND‐        │ pointcheck          │ cates if  OCSP  re‐ │
86          │POINTCHECK          │                     │ sponder   endpoints │
87          │                    │                     │ should not  be  re‐ │
88          │                    │                     │ quested   when   an │
89          │                    │                     │ OCSP  response   is │
90          │                    │                     │ not stapled.        │
91          └────────────────────┴─────────────────────┴─────────────────────┘
92
93   Configuration with mongoc_ssl_opt_t
94       Alternatively, the mongoc_ssl_opt_t struct may be used to configure TLS
95       with mongoc_client_set_ssl_opts() or mongoc_client_pool_set_ssl_opts().
96       Most of the configurable options can be set using the Connection String
97       URI.
98
99                 ┌───────────────────────┬──────────────────────────┐
100mongoc_ssl_opt_t key   URI key                  
101                 ├───────────────────────┼──────────────────────────┤
102                 │pem_file               │ tlsClientCertificateKey‐ │
103                 │                       │ File                     │
104                 ├───────────────────────┼──────────────────────────┤
105                 │pem_pwd                │ tlsClientCertificateKey‐ │
106                 │                       │ Password                 │
107                 ├───────────────────────┼──────────────────────────┤
108                 │ca_file                │ tlsCAFile                │
109                 ├───────────────────────┼──────────────────────────┤
110                 │weak_cert_validation   │ tlsAllowInvalidCertifi‐  │
111                 │                       │ cates                    │
112                 ├───────────────────────┼──────────────────────────┤
113                 │allow_invalid_hostname │ tlsAllowInvalidHostnames │
114                 └───────────────────────┴──────────────────────────┘
115
116       The only exclusions are crl_file and ca_dir. Those may only be set with
117       mongoc_ssl_opt_t.
118
119   Client Authentication
120       When MongoDB is started with TLS enabled, it will  by  default  require
121       the  client to provide a client certificate issued by a certificate au‐
122       thority specified by --tlsCAFile, or an authority trusted by the native
123       certificate store in use on the server.
124
125       To provide the client certificate, set the tlsCertificateKeyFile in the
126       URI to a PEM armored certificate file.
127
128          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
129          mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
130          mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "/path/to/client-certificate.pem");
131
132          mongoc_client_t *client = mongoc_client_new_from_uri (uri);
133
134   Server Certificate Verification
135       The MongoDB C Driver will automatically  verify  the  validity  of  the
136       server certificate, such as issued by configured Certificate Authority,
137       hostname validation, and expiration.
138
139       To overwrite this behavior, it is possible to disable hostname  valida‐
140       tion,  OCSP endpoint revocation checking, revocation checking entirely,
141       and allow invalid certificates.
142
143       This behavior is controlled using the tlsAllowInvalidHostnames, tlsDis‐
144       ableOCSPEndpointCheck, tlsDisableCertificateRevocationCheck, and tlsAl‐
145       lowInvalidCertificates options respectively. By default, all are set to
146       false.
147
148       It is not recommended to change these defaults as it exposes the client
149       to Man In The Middle attacks (when  tlsAllowInvalidHostnames  is  set),
150       invalid  certificates (when tlsAllowInvalidCertificates is set), or po‐
151       tentially revoked  certificates  (when  tlsDisableOCSPEndpointCheck  or
152       tlsDisableCertificateRevocationCheck are set).
153
154   Supported Libraries
155       By  default, libmongoc will attempt to find a supported TLS library and
156       enable TLS support. This is controlled by the  cmake  flag  ENABLE_SSL,
157       which is set to AUTO by default. Valid values are:
158
159AUTO  the  default behavior. Link to the system's native TLS library,
160         or attempt to find OpenSSL.
161
162DARWIN link to Secure Transport, the native TLS library on macOS.
163
164WINDOWS link to Secure Channel, the native TLS library on Windows.
165
166OPENSSL link to OpenSSL (libssl). An optional  install  path  may  be
167         specified with OPENSSL_ROOT.
168
169LIBRESSL link to LibreSSL's libtls. (LibreSSL's compatible libssl may
170         be linked to by setting OPENSSL).
171
172OFF disable TLS support.
173
174   OpenSSL
175       The MongoDB C Driver uses OpenSSL, if  available,  on  Linux  and  Unix
176       platforms (besides macOS). Industry best practices and some regulations
177       require the use of TLS 1.1 or newer, which requires  at  least  OpenSSL
178       1.0.1. Check your OpenSSL version like so:
179
180          $ openssl version
181
182       Ensure  your  system's OpenSSL is a recent version (at least 1.0.1), or
183       install a recent version in a non-system  path  and  build  against  it
184       with:
185
186          cmake -DOPENSSL_ROOT_DIR=/absolute/path/to/openssl
187
188       When compiled against OpenSSL, the driver will attempt to load the sys‐
189       tem default certificate store, as configured by the distribution.  That
190       can  be  overridden  by  setting  the  tlsCAFile URI option or with the
191       fields ca_file and ca_dir in the mongoc_ssl_opt_t.
192
193       The Online Certificate Status Protocol (OCSP) (see RFC 6960)  is  fully
194       supported when using OpenSSL 1.0.1+ with the following notes:
195
196       • When  a  crl_file  is set with mongoc_ssl_opt_t, and the crl_file re‐
197         vokes the server's certificate, the certificate is considered revoked
198         (even if the certificate has a valid stapled OCSP response)
199
200   LibreSSL / libtls
201       The  MongoDB C Driver supports LibreSSL through the use of OpenSSL com‐
202       patibility checks when configured to compile against openssl.  It  also
203       supports  the  new  libtls library when configured to build against li‐
204       bressl.
205
206       When compiled against the Windows native libraries, the crl_file option
207       of  a  mongoc_ssl_opt_t  is  not  supported, and will issue an error if
208       used.
209
210       Setting  tlsDisableOCSPEndpointCheck  and  tlsDisableCertificateRevoca‐
211       tionCheck has no effect.
212
213       The  Online  Certificate  Status Protocol (OCSP) (see RFC 6960) is par‐
214       tially supported with the following notes:
215
216       • The Must-Staple extension (see RFC 7633) is ignored.  Connection  may
217         continue  if  a  Must-Staple certificate is presented with no stapled
218         response (unless the client receives a revoked response from an  OCSP
219         responder).
220
221       • Connection  will  continue  if a Must-Staple certificate is presented
222         without a stapled response and the OCSP responder is down.
223
224   Native TLS Support on Windows (Secure Channel)
225       The MongoDB C Driver supports the Windows native  TLS  library  (Secure
226       Channel, or SChannel), and its native crypto library (Cryptography API:
227       Next Generation, or CNG).
228
229       When compiled against the Windows native libraries, the  ca_dir  option
230       of  a  mongoc_ssl_opt_t  is  not  supported, and will issue an error if
231       used.
232
233       Encrypted PEM files (e.g., setting tlsCertificateKeyPassword) are  also
234       not supported, and will result in error when attempting to load them.
235
236       When  tlsCAFile  is set, the driver will only allow server certificates
237       issued by the authority (or authorities) provided. When no tlsCAFile is
238       set, the driver will look up the Certificate Authority using the System
239       Local Machine Root certificate store to confirm the  provided  certifi‐
240       cate.
241
242       When  crl_file is set with mongoc_ssl_opt_t, the driver will import the
243       revocation list to the System Local Machine Root certificate store.
244
245       Setting tlsDisableOCSPEndpointCheck has no effect.
246
247       The Online Certificate Status Protocol (OCSP) (see RFC  6960)  is  par‐
248       tially supported with the following notes:
249
250       • The  Must-Staple  extension (see RFC 7633) is ignored. Connection may
251         continue if a Must-Staple certificate is presented  with  no  stapled
252         response  (unless the client receives a revoked response from an OCSP
253         responder).
254
255       • When a crl_file is set with mongoc_ssl_opt_t, and  the  crl_file  re‐
256         vokes  the  server's certificate, the OCSP response takes precedence.
257         E.g. if the server presents a certificate with a valid  stapled  OCSP
258         response,  the  certificate  is considered valid even if the crl_file
259         marks it as revoked.
260
261       • Connection will continue if a Must-Staple  certificate  is  presented
262         without a stapled response and the OCSP responder is down.
263
264   Native TLS Support on macOS / Darwin (Secure Transport)
265       The  MongoDB  C Driver supports the Darwin (OS X, macOS, iOS, etc.) na‐
266       tive TLS library (Secure Transport),  and  its  native  crypto  library
267       (Common Crypto, or CC).
268
269       When compiled against Secure Transport, the ca_dir and crl_file options
270       of a mongoc_ssl_opt_t are not supported. An error is issued  if  either
271       are used.
272
273       When  tlsCAFile  is set, the driver will only allow server certificates
274       issued by the authority (or authorities) provided. When no tlsCAFile is
275       set,  the  driver will use the Certificate Authorities in the currently
276       unlocked keychains.
277
278       Setting  tlsDisableOCSPEndpointCheck  and  tlsDisableCertificateRevoca‐
279       tionCheck has no effect.
280
281       The  Online  Certificate  Status Protocol (OCSP) (see RFC 6960) is par‐
282       tially supported with the following notes.
283
284       • The Must-Staple extension (see RFC 7633) is ignored.  Connection  may
285         continue  if  a  Must-Staple certificate is presented with no stapled
286         response (unless the client receives a revoked response from an  OCSP
287         responder).
288
289       • Connection  will  continue  if a Must-Staple certificate is presented
290         without a stapled response and the OCSP responder is down.
291

COMMON TASKS

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

ADVANCED CONNECTIONS

586       The  following  guide contains information specific to certain types of
587       MongoDB configurations.
588
589       For an example of connecting to a simple standalone server, see the Tu‐
590       torial.  To establish a connection with authentication options enabled,
591       see the Authentication page.
592
593   Connecting to a Replica Set
594       Connecting to a replica set is much like  connecting  to  a  standalone
595       MongoDB  server.  Simply specify the replica set name using the ?repli‐
596       caSet=myreplset URI option.
597
598          #include <bson/bson.h>
599          #include <mongoc/mongoc.h>
600
601          int
602          main (int argc, char *argv[])
603          {
604             mongoc_client_t *client;
605
606             mongoc_init ();
607
608             /* Create our MongoDB Client */
609             client = mongoc_client_new (
610                "mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset");
611
612             /* Do some work */
613             /* TODO */
614
615             /* Clean up */
616             mongoc_client_destroy (client);
617             mongoc_cleanup ();
618
619             return 0;
620          }
621
622       TIP:
623          Multiple hostnames can be specified in the MongoDB connection string
624          URI, with a comma separating hosts in the seed list.
625
626          It  is  recommended to use a seed list of members of the replica set
627          to allow the driver to connect to any node.
628
629   Connecting to a Sharded Cluster
630       To connect to a sharded cluster, specify the mongos  nodes  the  client
631       should  connect  to. The C Driver will automatically detect that it has
632       connected to a mongos sharding server.
633
634       If more than one hostname is specified, a seed list will be created  to
635       attempt failover between the mongos instances.
636
637       WARNING:
638          Specifying  the  replicaSet  parameter  when  connecting to a mongos
639          sharding server is invalid.
640
641          #include <bson/bson.h>
642          #include <mongoc/mongoc.h>
643
644          int
645          main (int argc, char *argv[])
646          {
647             mongoc_client_t *client;
648
649             mongoc_init ();
650
651             /* Create our MongoDB Client */
652             client = mongoc_client_new ("mongodb://myshard01:27017/");
653
654             /* Do something with client ... */
655
656             /* Free the client */
657             mongoc_client_destroy (client);
658
659             mongoc_cleanup ();
660
661             return 0;
662          }
663
664   Connecting to an IPv6 Address
665       The MongoDB C Driver will automatically  resolve  IPv6  addresses  from
666       host  names. However, to specify an IPv6 address directly, wrap the ad‐
667       dress in [].
668
669          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://[::1]:27017");
670
671   Connecting with IPv4 and IPv6
672       If connecting to a hostname that has both IPv4 and  IPv6  DNS  records,
673       the  behavior follows RFC-6555. A connection to the IPv6 address is at‐
674       tempted first. If IPv6 fails, then a connection  is  attempted  to  the
675       IPv4  address.  If  the  connection  attempt  to IPv6 does not complete
676       within 250ms, then IPv4 is tried in parallel. Whichever  succeeds  con‐
677       nection  first  cancels  the other. The successful DNS result is cached
678       for 10 minutes.
679
680       As a consequence, attempts to connect to a  mongod  only  listening  on
681       IPv4  may  be  delayed  if  there are both A (IPv4) and AAAA (IPv6) DNS
682       records associated with the host.
683
684       To avoid a delay, configure hostnames to match the  MongoDB  configura‐
685       tion.  That is, only create an A record if the mongod is only listening
686       on IPv4.
687
688   Connecting to a UNIX Domain Socket
689       On UNIX-like systems, the C Driver can connect directly  to  a  MongoDB
690       server  using  a  UNIX  domain socket. Pass the URL-encoded path to the
691       socket, which must be suffixed with .sock. For example, to connect to a
692       domain socket at /tmp/mongodb-27017.sock:
693
694          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://%2Ftmp%2Fmongodb-27017.sock");
695
696       Include username and password like so:
697
698          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://user:pass@%2Ftmp%2Fmongodb-27017.sock");
699
700   Connecting to a server over TLS
701       These are instructions for configuring TLS/SSL connections.
702
703       To run a server locally (on port 27017, for example):
704
705          $ mongod --port 27017 --tlsMode requireTLS --tlsCertificateKeyFile server.pem --tlsCAFile ca.pem
706
707       Add /?tls=true to the end of a client URI.
708
709          mongoc_client_t *client = NULL;
710          client = mongoc_client_new ("mongodb://localhost:27017/?tls=true");
711
712       MongoDB requires client certificates by default, unless the --tlsAllow‐
713       ConnectionsWithoutCertificates is provided. The C Driver can be config‐
714       ured  to  present a client certificate using the URI option tlsCertifi‐
715       cateKeyFile,  which  may  be  referenced  through  the  constant   MON‐
716       GOC_URI_TLSCERTIFICATEKEYFILE.
717
718          mongoc_client_t *client = NULL;
719          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/?tls=true");
720          mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "client.pem");
721
722          client = mongoc_client_new_from_uri (uri);
723
724       The client certificate provided by tlsCertificateKeyFile must be issued
725       by  one  of  the  server  trusted  Certificate  Authorities  listed  in
726       --tlsCAFile,  or  issued by a CA in the native certificate store on the
727       server when omitted.
728
729       See configuring_tls for more information on the various TLS related op‐
730       tions.
731
732   Compressing data to and from MongoDB
733       MongoDB  3.4 added Snappy compression support, zlib compression in 3.6,
734       and zstd compression in 4.2.  To enable compression support the  client
735       must be configured with which compressors to use:
736
737          mongoc_client_t *client = NULL;
738          client = mongoc_client_new ("mongodb://localhost:27017/?compressors=snappy,zlib,zstd");
739
740       The  compressors option specifies the priority order of compressors the
741       client wants to use. Messages are compressed if the client  and  server
742       share any compressors in common.
743
744       Note  that the compressor used by the server might not be the same com‐
745       pressor as the client used.  For example, if the client uses  the  con‐
746       nection  string  compressors=zlib,snappy  the client will use zlib com‐
747       pression to send data (if possible), but the server might  still  reply
748       using snappy, depending on how the server was configured.
749
750       The driver must be built with zlib and/or snappy and/or zstd support to
751       enable compression support, any unknown (or not compiled in) compressor
752       value  will be ignored. Note: to build with zstd requires cmake 3.12 or
753       higher.
754
755   Additional Connection Options
756       The full list of connection options can be found  in  the  mongoc_uri_t
757       docs.
758
759       Certain socket/connection related options are not configurable:
760
761             ┌──────────────┬─────────────────────┬─────────────────────┐
762             │Option        │ Description         │ Value               │
763             ├──────────────┼─────────────────────┼─────────────────────┤
764             │SO_KEEPALIVE  │ TCP Keep Alive      │ Enabled             │
765             ├──────────────┼─────────────────────┼─────────────────────┤
766             │TCP_KEEPIDLE  │ How  long a connec‐ │ 120 seconds         │
767             │              │ tion needs  to  re‐ │                     │
768             │              │ main   idle  before │                     │
769             │              │ TCP starts  sending │                     │
770             │              │ keepalive probes    │                     │
771             ├──────────────┼─────────────────────┼─────────────────────┤
772             │TCP_KEEPINTVL │ The time in seconds │ 10 seconds          │
773             │              │ between TCP probes  │                     │
774             ├──────────────┼─────────────────────┼─────────────────────┤
775             │TCP_KEEPCNT   │ How many probes  to │ 9 probes            │
776             │              │ send,  without  ac‐ │                     │
777             │              │ knowledgement,  be‐ │                     │
778             │              │ fore  dropping  the │                     │
779             │              │ connection          │                     │
780             ├──────────────┼─────────────────────┼─────────────────────┤
781             │TCP_NODELAY   │ Send   packets   as │ Enabled (no buffer‐ │
782             │              │ soon as possible or │ ing)                │
783             │              │ buffer small  pack‐ │                     │
784             │              │ ets   (Nagle  algo‐ │                     │
785             │              │ rithm)              │                     │
786             └──────────────┴─────────────────────┴─────────────────────┘
787

CONNECTION POOLING

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

CURSORS

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

BULK WRITE OPERATIONS

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

AGGREGATION FRAMEWORK EXAMPLES

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

DISTINCT AND MAPREDUCE

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

USING LIBMONGOC IN A MICROSOFT VISUAL STUDIO PROJECT

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

CREATING INDEXES

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

AIDS FOR DEBUGGING

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

USING CLIENT-SIDE FIELD LEVEL ENCRYPTION

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

AUTHOR

4151       MongoDB, Inc
4152
4154       2017-present, MongoDB, Inc
4155
4156
4157
4158
41591.20.0                           Nov 18, 2021                 MONGOC_GUIDES(3)
Impressum