Provided by: libmongoc-doc_1.26.0-1.1ubuntu2_all bug

LIBMONGOC

       A Cross Platform MongoDB Client Library for C

   Introduction
       The  MongoDB  C  Driver,  also known as "libmongoc", is a library for using MongoDB from C
       applications, and for writing MongoDB drivers in higher-level languages.

       It depends on libbson to generate and parse BSON documents,  the  native  data  format  of
       MongoDB.

   Tutorials
       This  section  contains  tutorials  on  how  to get started with the basics of using the C
       driver.

   Obtaining the MongoDB C Driver Libraries
       There are a few methods of obtaining the mongo-c-driver codebase:

   Building the C Driver Libraries from Source
       This page details how to download, unpack, configure, and build libbson and libmongoc from
       their original source-code form.

       Extra information

       Dropdowns  (like  this one) contain extra information and explanatory details that are not
       required to complete the tutorial, but may  be  helpful  for  curious  readers,  and  more
       advanced users that want an explanation of the meaning of certain tutorial steps.

       The  following  page uses a few named "variables" that you must decide up-front.  When you
       see such a value referrenced in a tutorial step, you should substitute the value into that
       step.

       SEE ALSO:
          Before  building,  you  may want to check that you are running on a supported platform.
          For the list of supported platforms, refer to the mongo-c-driver Platform Support page.

   Choose a Version
       Before we begin, know what version of mongo-c-driver you will be downloading.  A  list  of
       available  versions  can be found on the GitHub repository tags page. (The current version
       written for this documentation is 1.26.0.)

       For  the  remainder  of  this  page,  $VERSION  will  refer  to  the  version  number   of
       mongo-c-driver that you will be building for this tutorial.

   Obtaining the Source
       There are two primary recommended methods of obtaining the mongo-c-driver source code:

       1. Clone the repository using git (recommended).  (See below)

       2. Download a source archive at a specific version.  (See below)

       IMPORTANT:
          It  is  highly  recommended that new users use a stable released version of the driver,
          rather than building from a development branch. When  you  git  clone  or  download  an
          archive  of  the repository, be sure to specify a release tag (e.g. with Git's --branch
          argument).

   Downloading Using Git
       Using  Git,  the   C   driver   repository   can   be   cloned   from   the   GitHub   URL
       https://github.com/mongodb/mongo-c-driver.git.  Git  tags  for released versions are named
       after the version for which they correspond (e.g. "1.26.0"). To clone the repository using
       the command line, the following command may be used:

          $ git clone https://github.com/mongodb/mongo-c-driver.git --branch="$VERSION" "$SOURCE"

       TIP:
          Despite  the  name,  git-clone's  --branch  argument  may  also  be  used to clone from
          repository tags.

   Downloading a Release Archive
       An archived snapshot of the repository can be obtained from the GitHub Releases Page.  The
       mongo-c-driver-x.y.z.tar.gz  archive  attached  to any release contains the minimal set of
       files that you'll need for the build.

       Using wget + tar

          ## Download using wget:
          $ wget "https://github.com/mongodb/mongo-c-driver/archive/refs/tags/$VERSION.tar.gz" \
              --output-document="mongo-c-driver-$VERSION.tar.gz"
          ## Extract using tar:
          $ tar xf "mongo-c-driver-$VERSION.tar.gz"

       Using curl + tar

          ## Using curl:
          $ curl "https://github.com/mongodb/mongo-c-driver/archive/refs/tags/$VERSION.tar.gz" \
              --output="mongo-c-driver-$VERSION.tar.gz"
          ## Extract using tar:
          $ tar xf "mongo-c-driver-$VERSION.tar.gz"

       PowerShell

          ## Use Invoke-WebRequest:
          PS> $url = "https://github.com/mongodb/mongo-c-driver/archive/refs/tags/$VERSION.zip"
          PS> $file = "mongo-c-driver-$VERSION.zip"
          PS> Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $file
          ## Extract using Expand-Archive:
          PS> Expand-Archive mongo-c-driver-$VERSION.zip

       The above  commands  will  create  a  new  directory  mongo-c-driver-$VERSION  within  the
       directory in which you ran the tar/Expand-Archive command (note: PowerShell will create an
       additional intermediate subdirectory of the same name). This directory is the root of  the
       driver  source  tree  (which  we  refer  to  as  $SOURCE  in these documents). The $SOURCE
       directory should contain the top-level CMakeLists.txt file.

   Obtaining Prerequisites
       In order to build the project, a few prerequisites need to be available.

       Both libmongoc and libbson projects use CMake for build configuration.

       NOTE:
          It is highly recommended -- but not required -- that you  download  the  latest  stable
          CMake available for your platform.

       Getting the Latest CMake

       A new stable release of CMake can be obtained from the CMake downloads page.

       For  Windows and macOS, simply download the CMake .msi/.dmg (not the .zip/.tar.gz) and use
       it to install CMake.

       On Linux, download the self-extracting shell script (ending with .sh) and execute it using
       the  sh  utility,  passing  the appropriate arguments to perform the install. For example,
       with the CMake 3.27.0 on the x86_64 platform, the following command can  be  used  on  the
       cmake-3.27.0-linux-x86_64.sh script:

          $ sh cmake-3.27.0-linux-x86_64.sh --prefix="$HOME/.local" --exclude-subdir --skip-license

       Assuming  that  $HOME/.local/bin  is on your $PATH list, the cmake command for 3.27.0 will
       then become available.

       The --help option can be passed to the shell script for more information.

       For the remainder of this page, it will be assumed that cmake is available as a command on
       your  PATH  environment variable and can be executed as "cmake" from a shell. You can test
       this by requesting the --version from CMake from the command line:

          $ cmake --version
          cmake version 3.21.4

          CMake suite maintained and supported by Kitware (kitware.com/cmake).

       NOTE:
          If you intend to build libbson only, then CMake is sufficient for the build. Additional
          C  driver  features  may  require additional external dependencies be installed, but we
          will not worry about them here.

   Configuring for libbson
       IMPORTANT:
          If you are building with Xcode [1] or Visual Studio [2], you may need to execute  CMake
          from within a special environment in which the respective toolchain is available.

       Let the name $BUILD be the path $SOURCE/_build. This will be the directory where our built
       files will be written by CMake.

       With the source directory for mongo-c-driver at $SOURCE and build  directory  $BUILD,  the
       following  command  can be executed from a command-line to configure the project with both
       libbson and libmongoc:

          $ cmake -S $SOURCE -B $BUILD \
            -D ENABLE_EXTRA_ALIGNMENT=OFF \
            -D ENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF \
            -D CMAKE_BUILD_TYPE=RelWithDebInfo \
            -D BUILD_VERSION="$VERSION" \
            -D ENABLE_MONGOC=OFF

       If all dependencies are satisfied, the above command should succeed and end with:

          $ cmake …
          ## … (Lines of output) …
          -- Generating done
          -- Build files have been written to: $BUILD

       If configuration failed with an error, refer to the CMake output for  error  messages  and
       information. Ensure that configuration succeeds before proceeding.

       What do these CMake arguments mean?

       The BUILD_VERSION sets the version number that will be included in the build results. This
       should be set to the same value as the version of the source driver that was downloaded in
       Obtaining the Source.

       The    ENABLE_EXTRA_ALIGNMENT    and   ENABLE_AUTOMATIC_INIT_AND_CLEANUP   are   part   of
       mongo-c-driver, and correspond to deprecated features that are only enabled by default for
       ABI  compatibility  purposes.  It is highly recommended to disable these features whenever
       possible.

       The ENABLE_MONGOC=OFF argument disabled building libmongoc. We'll build that in  the  next
       section.

       The  CMAKE_BUILD_TYPE  setting  tells CMake what variant of code will be generated. In the
       case of RelWithDebInfo, optimized binaries will  be  produced,  but  still  include  debug
       information.  The  CMAKE_BUILD_TYPE  has no effect on Multi-Config generators (i.e. Visual
       Studio), which instead rely on the --config option when building/installing.

   Building the Project
       After successfully configuring the project, the build can be executed by using CMake:

          $ cmake --build $BUILD --config RelWithDebInfo --parallel

       If configured properly and all dependencies are satisfied, then the above  command  should
       proceed  to  compile  and link the configured components. If the above command fails, then
       there is likely an error with your environment, or you are using  an  unsupported/untested
       platform. Refer to the build tool output for more information.

       The --config option

       The  --config  option  is  used  to  set  the  build  configuration  to use in the case of
       Multi-Config generators (i.e. Visual Studio). It has no effect on other generators,  which
       instead use CMAKE_BUILD_TYPE.

   Installing the Built Results
       Let $PREFIX be the path $SOURCE/_install. We can use CMake to install the built results:

          $ cmake --install "$BUILD" --prefix "$PREFIX" --config RelWithDebInfo

       This command will install the mongo-c-driver build results into the $PREFIX directory.

       The --config option

       The  --config  option is only used for Multi-Config generators (i.e. Visual Studio) and is
       otherwise ignored. The value given for --config must be the same as was given for --config
       with cmake --build.

       SEE ALSO:
          The  above  snippet  simply  installs  mongo-c-driver  in  a subdirectory of the source
          directory itself, but this is not a normal workflow. Once you feel  compfortable  about
          configuring  and  building  mongo-c-driver,  the page How to: Install libbson/libmongoc
          from Source will do a deeper dive on from-source installation options.

   Configuring with libmongoc
       If you followed the above steps starting from Configuring for libbson, your  final  result
       with  only  contain  libbson  and  not  the  full  C  database driver library. Building of
       libmongoc is enabled/disabled using the ENABLE_MONGOC CMake variable. Re-run CMake  again,
       but set ENABLE_MONGOC to TRUE:

          $ cmake -D ENABLE_MONGOC=ON $BUILD

       If  the  above  command  succeeds,  then  the  project has been reconfigured to build with
       libmongoc. Follow the process at Building the Project and  Installing  the  Built  Results
       again to build and install libmongoc.

FOOTNOTES

       [1]  If  you  wish  to  configure and build the project with Xcode, the Xcode command-line
            tools need to be installed and made available in  the  environment.   From  within  a
            command-line environment, run:

          $ xcode-select --install

       This will ensure that the compilers and linkers are available on your $PATH.

       [2]  If  you  wish to configure and build the project using Microsoft Visual C++, then the
            Visual C++ tools and environment variables may need to be set when running any  CMake
            or build command.

            In  many cases, CMake will detect a Visual Studio installation and automatically load
            the environment  itself  when  it  is  executed.  This  automatic  detection  can  be
            controlled  with  CMake's  -G,  -T,  and  -A  options.  The  -G  option  is  the most
            significant, as it selects which Visual Studio version will be used. The versions  of
            Visual  Studio  supported depends on the version of CMake that you have installed.  A
            list of supported Visual Studio versions can be found here

            For greater control and more tooling options, it is recommended to run commands  from
            within  a  Visual Studio Developer PowerShell (preferred) or Developer Command Prompt
            (legacy).

            For more information, refer to: Visual Studio Developer Command Prompt and  Developer
            PowerShell  and  Use the Microsoft C++ toolset from the command line on the Microsoft
            Visual Studio documentation pages.

   Installing Prebuilt MongoDB C Driver Libraries
       The libmongoc and  libbson  libraries  are  often  available  in  the  package  management
       repositories of common Linux distributions and macOS via Homebrew.

       NOTE:
          For  Windows, it is recommended to instead build the libraries from source, for maximum
          compatibility with the local toolchain. Building from source can be automated by  using
          a  from-source  library  package  management  tool  such  as Conan or vcpkg (See: Cross
          Platform Installs Using Library Package Managers).

       CAUTION:
          If you install and use prebuilt binaries from a third-party packager,  it  is  possible
          that it lags behind the version of the libraries described in these documentation pages
          (1.26.0). Note the version that you install and keep it  in  mind  when  reading  these
          pages.

          For  the  most  up-to-date  versions of the C driver libraries, prefer to instead build
          from source.

       SEE ALSO:
          For a listing and common reference on available packages, refer to Package Installation
          Reference.

   Cross Platform Installs Using Library Package Managers
       Various  library  package  managers  offer  libbson and libmongoc as installable packages,
       including Conan and vcpkg. This section will detail how to install using those tools.

   Installing using vcpkg
       NOTE:
          This page will not detail how to get started  using  vcpkg.  For  that,  refer  to  Get
          started with vcpkg

       vcpkg  Manifest  Mode  (Recommended)  In vcpkg manifest mode, add the desired libraries to
       your project's vcpkg.json manifest file:

       vcpkg.json

          {
            // ...
            "dependencies": [
              // ...
              "mongo-c-driver"
            ]
          }

       When you build a CMake project with vcpkg integration and have a vcpkg.json manifest file,
       vcpkg  will  automatically  install  the project's dependencies before proceeding with the
       configuration phase, so no additional manual work is required.

       vcpkg Classic Mode In vcpkg classic mode, libbson and libmongoc can be  installed  through
       the names libbson and mongo-c-driver, respectively:

          $ vcpkg install mongo-c-driver

       (Installing mongo-c-driver will transitively install libbson as well.)

       When  the  libmongoc  and  libbson  packages  are  installed  and  vcpkg has been properly
       integrated into your build system, the desired libraries will be available for import.

       With CMake, the standard config-file package will be available, as well as  the  generated
       IMPORTED targets:

       CMakeLists.txt

          find_package(mongoc-1.0 CONFIG REQUIRED)
          target_link_libraries(my-application
              PRIVATE $<IF:$<TARGET_EXISTS:mongo::mongoc_shared>,mongo::mongoc_shared,mongo::mongoc_static>)

       NOTE:
          The      large      $<IF:$<TARGET_EXISTS...>:...>      generator      expression     (‐
          cmake-generator-expressions(7)) can be used to switch the link type of libmongoc  based
          on  whichever  form  is  available  from the find_package() command. libmongoc supports
          building with both dynamic and static library types, but vcpkg will only install one of
          the two library types at a time.

       Configuring  a  CMake  project  with  vcpkg  integration  is a matter of setting the CMake
       toolchain file at the initial configure command:

          $ cmake -S . -B _build -D CMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake

   Installing in Linux
       The names and process of installing libbson and libmongoc  varies  between  distributions,
       but generally follows a similar pattern.

       The following Linux distributions provide libbson and libmongoc packages:

       • Fedora via dnfRedHat  Enterprise  Linux (RHEL) 7 and Newer and distribusions based on RHEL 7 or newer,
         including CentOS, Rocky Linux, and AlmaLinux, via yum/dnf and EPEL.

       • Debian and Debian-based distributions, including Ubuntu and Ubuntu derivatives, via APT.

       SEE ALSO:
          For a list of  available  packages  and  package  options,  see:  Package  Installation
          Reference.

   RedHat-based Systems
       In RedHat-based Linux distributions, including Fedora, CentOS, Rocky Linux, and AlmaLinux,
       the C driver libraries can be installed with Yum/DNF.

       NOTE:
          For Fedora and enterprise Linux of version 8 or greater, it is recommended to  use  the
          dnf command in place of any yum command.

       IMPORTANT:
          Except for Fedora:

          The  C  driver  libraries  are  only available in version 7 and newer of the respective
          enterprise Linux distributions. However, the C driver libraries are  not  available  in
          the  default  repositories, but can be obtained by enabling the EPEL repositories. This
          can be done by installing the epel-release package:

              # yum install epel-release

          epel-release must be installed before attempting to  install  the  C  driver  libraries
          (i.e. one cannot install them both in a single yum install command).

       To install libbson only, install the libbson-devel package:

          # yum install libbson-devel

       To install the full C database driver (libmongoc), install mongo-c-driver-devel:

          ## (This package will transitively install libbson-devel)
          # yum install mongo-c-driver-devel

       To          check          which         version         is         available,         see
       https://packages.fedoraproject.org/pkgs/mongo-c-driver/mongo-c-driver-devel.

       The development packages (ending in -devel) include files required to  build  applications
       using  libbson  and  libmongoc.   To only install the libraries without development files,
       install the libbson or mongo-c-driver-libs packages.

   Debian-based Systems
       In Debian-based Linux distributions, including Ubuntu and Ubuntu derivatives, libbson  and
       libmongoc  are available in the distribution repositories via APT, and can be installed as
       libbson-dev and libmongoc-dev, respectively:

          ## Update repository information, if necessary:
          # apt update

       To install only libbson:

          # apt install libbson-dev

       To install libmongoc (which will also install libbson):

          # apt install libmongoc-dev

       To check which version is available, run apt-cache policy libmongoc-dev.

       The development packages (ending in -dev) include files  required  to  build  applications
       using  libbson  and  libmongoc.   To only install the libraries without development files,
       install the libbson-1.0-0 or libmongoc-1.0-0 packages.

   Installing on macOS with Homebrew
       If you are using a macOS system, the C driver  libraries  (including  both  libmongoc  and
       libbson)  may  be  installed  using  the  Homebrew  package manager [1] with the following
       command:

          $ brew install mongo-c-driver

       NOTE:
          Homebrew does not provide separate packages for libbson and libmongoc.

       [1]  The Homebrew package manager is not installed by default on macOS. For information on
            installing Homebrew, refer to the Homebrew installation documentation page.

   Building the mongo-c-driver Documentation Pages
       This  documentation  is  rendered  using Sphinx. To easily ensure that all tooling matches
       expected versions, it is recommended to use Poetry to install and run the required tools.

       TIP:
          Poetry itself may be installed externally, but can also be automatically managed  using
          the  included  wrapping  scripts  for  Bash  (At  tools/poetry.sh)  or  PowerShell  (at
          tools/poetry.ps1). These scripts can stand in for poetry in any command written below.

   Setting Up the Environment
       To install the required tooling, use the poetry install  command,  enabling  documentation
       dependencies:

          $ poetry install --with=docs

       This  will  create  a  user-local  Python virtualenv that contains the necessary tools for
       building this documentation. The poetry install command only needs  to  be  run  when  the
       pyproject.toml file is changed.

   Running Sphinx
       Poetry can be used to execute the sphinx-build command:

          $ poetry run sphinx-build -b dirhtml "./src/libmongoc/doc" "./_build/docs/html"

       This command will generate the HTML documentation in the _build/docs/html subdirectory.

       TIP:
          Because Sphinx builds many pages, the build may run quite slowly. For faster builds, it
          is recommended to use the --jobs command-line option when invoking sphinx-build.

   Viewing the Documentation
       To quickly view the rendered HTML pages, a simple local HTTP server can be spawned on  the
       command line by using Python's built-in http.server module:

          $ poetry run python -m http.server --directory=_build/docs/html

       By default, this will serve the documentation at http://127.0.0.1:8000, which you can open
       in any web browser to see the rendered pages.

   How-To Guides
       IMPORTANT:
          The "cookbook" is for problem-solving, and deeper dives into approach particular tasks.
          It  may  assume  some  prior  knowledge,  and  these  are not tutorials themselves! For
          learning the basics, see the Tutorials section.

   How to: Install libbson/libmongoc from Source
       IMPORTANT:
          This page assumes that you can successfully configure and build the components that you
          wish to install, which is detailed and explained on the Building the C Driver Libraries
          from Source tutorial page. Whereas that tutorial  walks  through  getting  the  sources
          built and a minimal install working, this page will offer deeper guidance on the nuance
          and  available  options  for  installing  the  mongo-c-driver  libraries  from  such  a
          from-source build.

       mongo-c-driver  uses  CMake  to generate its installation rules, and installs a variety of
       artifacts of interest. For integration with downstream programs, the Config-file  Packages
       and pkg-config files would be of particular interest.

       If  you  are  intending  to import libbson or libmongoc via CMake or pkg-config, it can be
       helpful to be aware of how the respective tool searches for package metadata.

       CMake Package Lookup CMake builds a set of search paths based on a set of prefixes,  which
       are read from both the environment and from configure-time CMake settings.

       In  particular,  the  $PATH  environment  variable  will be used to construct the standard
       prefixes for the system. For each directory D in $PATH:

       1. If the final path component of D is "bin" or "sbin", D is replaced with the parent path
          of D.

       2. D is added as a search prefix.

       This  has  the effect that common Unix-specific directories on $PATH, such as /usr/bin and
       /usr/local/bin will end up causing CMake to search in /usr  and  /usr/local  is  prefixes,
       respectively.  If  you  have  the  directory  $HOME/.local/bin  on  your  $PATH,  then the
       $HOME/.local directory will also be added to the search path. Having  $HOME/.local/bin  on
       $PATH  is  an  increasingly common pattern for many Unix shells, and is recommended if you
       intend to do use a per-user-prefix for your installion.

       Additionally, the CMAKE_PREFIX_PATH environment variable will be used to construct a  list
       of paths. By default, this environment variable is not defined.

       On   Windows,   the   directories   %ProgramW6432%,  %ProgramFiles%,  %ProgramFiles(x86)%,
       %SystemDrive%\Program Files, and %SystemDrive%\Program Files (x86)  will  also  be  added.
       (These  come  from  the  CMAKE_SYSTEM_PREFIX_PATH  CMake variable, which is defined during
       CMake's platform detection.)

       SEE ALSO:
          For detailed information on  package  lookup,  refer  to  CMake's  Config  Mode  Search
          Procedure section for full details.

       pkg-config  Package Lookup The pkg-config command-line tool looks for .pc files in various
       directories, by default relative to the path of the pkg-config tool  itself.  To  get  the
       list  of  directories  that  your  pkg-config  will  search  by default, use the following
       command:

       Ask pkg-config what directories it will search by default

          $ pkg-config "pkg-config" --variable="pc_path"

       Additional directories can be specified using the $PKG_CONFIG_PATH  environment  variable.
       Such paths will be searched before the default pkg-config paths.

       On      Windows,     registry     keys     HKCU\Software\pkgconfig\PKG_CONFIG_PATH     and
       HKLM\Software\pkgconfig\PKG_CONFIG_PATH  can  be  used  to   specify   additional   search
       directories  for  pkg-config.  Adding  directories  to  the  HKCU\… key is recommended for
       persisting user-specific search directories.

       SEE ALSO:
          If you have man and pkg-config installed on your system, lookup procedures are detailed
          in  man 1 pkg-config. This documentation may also be found at many man page archives on
          the web, such as pkg-config at linux.die.net.

   Choosing a Prefix
       We will call the directory for the user-local installation $PREFIX. Selecting the path  to
       this  directory is somewhat arbitrary, but there are some recommendations to consider. The
       $PREFIX directory is the path that you will give to CMake or pkg-config when configuring a
       downstream project.

   Using an Unprivileged User-Local Install Prefix (Recommended)
       It   is   recommended  that  you  install  custom-built  mongo-c-driver  libraries  in  an
       unprivileged filesystem location particular to the user account.

       macOS Unlike other Unix-like systems,  macOS  does  not  have  a  specific  directory  for
       user-local  package  installations,  and  it  is  up  to  the  individual  to  create such
       directories themselves.

       The choice of directory to use is essentially arbitrary. For per-user  installations,  the
       only requirement is that the directory be writeable by the user that wishes to perform and
       use the installation.

       For the purposes of uniformity with other Unix variants, this guide will lightly recommend
       using  $HOME/.local  as  a  user-local installation prefix.  This is based on the behavior
       specified by the XDG base directory specifications and the systemd  file-hierarchy  common
       on Linux and various BSDs, but it is not a standard on other platforms.

       Linux  &  Other  Unixes  On  Linux  and  BSD systems, it is common to use the $HOME/.local
       directory  as  the  prefix  for  user-specific  package  installations.  This   convention
       originates in the XDG base directory specification and the systemd file-hierarchy

       Because  of  its  wide-spread  use  and support in many other tools, this guide recommends
       using $HOME/.local as a user-local installation prefix.

       Windows  On  Windows,  there  exists  a  dedicated  directory  for  user-local  files   in
       %UserProfile%\AppData\Local.  To  reference  it,  expand  the  %LocalAppData%  environment
       variable. (Do not use the %AppData% environment variable!)

       Despite this directory existing, it has no prescribed structure that suits  our  purposes.
       The   choice  of  user-local  installation  prefix  is  arbitrary.   This  guide  strongly
       discourages creating additional files and directories  directly  within  the  user's  home
       directory.

       Consider  using  %LocalAppData%\MongoDB as a prefix for the purposes of manually installed
       components.

   Selecting a System-Wide Installation Prefix
       If you wish to install the mongo-c-driver libraries in a directory that is visible to  all
       users, there are a few standard options.

       Linux,  macOS,  BSD,  or Other Unix Using an install $PREFIX of /usr/local/ is the primary
       recommendation for all Unix platforms, but this may vary on some obscure systems.

       WARNING:
          DO NOT use /usr/ nor / (the root directory) as a prefix: These directories are designed
          to  be  carefully  managed  by  the  system.  The /usr/local directory is intentionally
          reserved for the purpose of unmanaged software installation.

       Alternatively, consider installing to a distinct directory that can be easily  removed  or
       relocated, such as /opt/mongo-c-driver/. This will be easily identifiable and not interact
       with other software on the system without explicitly opting-in.

       Windows

       WARNING:
          It is strongly discouraged to manually install software system-wide on Windows.  Prefer
          instead to use a per-user unprivileged installation prefix.

       If  you  wish  to  perform  a  system-wide  installation on Windows, prefer to use a named
       subdirectory of %ProgramData%, which does not require administrative  privileges  to  read
       and write. (e.g.  %ProgramData%\mongo-c-driver)

   Installing with CMake
       After  you  have  successfully  configured  and  built  the  libraries and have selected a
       suitable $PREFIX, you can install the built results. Let the  name  $BUILD  refer  to  the
       directory   where   you   executed   the  build  (this  is  the  directory  that  contains
       CMakeCache.txt, among many other files).

       From a command line, the installation into your chosen $PREFIX can be run via CMake  using
       the cmake --install subcommand:

          $ cmake --install "$BUILD" --prefix "$PREFIX"

       IMPORTANT:
          If  you  configured  the  libraries  while  using  a multi-config generator (e.g Visual
          Studio, Xcode), then you will also need to pass the --config command-line  option,  and
          must  pass  the  value  for  the  build configuration that you wish to install. For any
          chosen value of --config used for installation, you must also have previously  executed
          a cmake --build within that directory with that same --config value.

       NOTE:
          If  you  chose  to use a system-wide installation $PREFIX, it is possible that you will
          need to execute the installation as a privileged user. If you cannot run or do not want
          to  run  the  installation  as  a  privileged  user,  you should instead use a per-user
          installation prefix.

       HINT:
          It is not necessary to set a CMAKE_INSTALL_PREFIX if you use the --prefix  command-line
          option  with  cmake --install. The --prefix option will override whatever was specified
          by CMAKE_INSTALL_PREFIX when the project was configured.

   Reference
   Package Installation Reference
       libbson and libmongoc are available from several package management tools on a variety  of
       systems.

       IMPORTANT:
          The   third-party   packages   detailed  here  are  not  directly  controlled  via  the
          mongo-c-driver maintainers, and  the  information  found  here  may  be  incomplete  or
          out-of-date.

   Package Names and Availability
       This table details the names and usage notes of such packages.

       NOTE:
          The  development  packages  (ending  in -dev or -devel) include files required to build
          applications using libbson and libmongoc.

       SEE ALSO:
          For a step-by-step tutorial  on  installing  packages,  refer  to  Installing  Prebuilt
          MongoDB C Driver Libraries.

     ┌───────────────┬──────────────────┬────────────────┬───────────────────────┬──────────────────┐
     │Packaging Tool │ Platform(s)      │ libbsonlibmongoc             │ Notes            │
     │               │                  │ package(s)     │ package(s)            │                  │
     ├───────────────┼──────────────────┼────────────────┼───────────────────────┼──────────────────┤
     │APT            │ Debian-based     │ libbson-1.0-0, │ libmongoc-1.0-0,      │                  │
     │(apt/apt-get)  │ Linux            │ libbson-dev,   │ libmongoc-dev,        │                  │
     │               │ distributions    │ libbson-doclibmongoc-doc         │                  │
     │               │ (Debian, Ubuntu, │                │                       │                  │
     │               │ Linux      Mint, │                │                       │                  │
     │               │ etc.)            │                │                       │                  │
     ├───────────────┼──────────────────┼────────────────┼───────────────────────┼──────────────────┤
     │Yum/DNF        │ RHEL-based       │ libbson,       │ mongo-c-driver-libs,  │ Except on Fedora │
     │               │ systems   (RHEL, │ libbson-develmongo-c-driver-devel  │ the         EPEL │
     │               │ Fedora,  CentOS, │                │                       │ repositories     │
     │               │ Rocky     Linux, │                │                       │ must  be enabled │
     │               │ AlmaLinux)       │                │                       │ (i.e.    install │
     │               │                  │                │                       │ the epel-release │
     │               │                  │                │                       │ package first)   │
     ├───────────────┼──────────────────┼────────────────┼───────────────────────┼──────────────────┤
     │APK            │ Alpine Linux     │ libbson,       │ mongo-c-driver,       │                  │
     │               │                  │ libbson-dev,   │ mongo-c-driver-dev,   │                  │
     │               │                  │ libbson-staticmongo-c-driver-static │                  │
     ├───────────────┼──────────────────┼────────────────┼───────────────────────┼──────────────────┤
     │pacman         │ Arch Linux       │ mongo-c-drivermongo-c-driver        │ A single package │
     │               │                  │                │                       │ provides    both │
     │               │                  │                │                       │ runtime      and │
     │               │                  │                │                       │ development      │
     │               │                  │                │                       │ support for both │
     │               │                  │                │                       │ libbson      and │
     │               │                  │                │                       │ libmongoc        │
     ├───────────────┼──────────────────┼────────────────┼───────────────────────┼──────────────────┤
     │Homebrew       │ macOS            │ mongo-c-drivermongo-c-driver        │                  │
     ├───────────────┼──────────────────┼────────────────┼───────────────────────┼──────────────────┤
     │Conan          │ Cross-platform   │ mongo-c-drivermongo-c-driver        │ See:       Conan │
     │               │                  │                │                       │ Settings     and │
     │               │                  │                │                       │ Features         │
     ├───────────────┼──────────────────┼────────────────┼───────────────────────┼──────────────────┤
     │vcpkg          │ Cross-platform   │ libbsonmongo-c-driver        │ See:       vcpkg │
     │               │                  │                │                       │ Optional         │
     │               │                  │                │                       │ Features         │
     └───────────────┴──────────────────┴────────────────┴───────────────────────┴──────────────────┘

   Conan Settings and Features
       The  mongo-c-driver  Conan  recipe  includes several build settings that correspond to the
       configure-time build settings available when building the mongo-c-driver project.

       SEE ALSO:
          The mongo-c-driver Conan recipe (includes libbson)

            ┌────────────┬─────────────────────┬─────────────────────┬──────────────────────┐
            │Setting     │ Options             │ Default             │ Notes                │
            ├────────────┼─────────────────────┼─────────────────────┼──────────────────────┤
            │shared      │ (Boolean)           │ False               │ Build  the   shared  │
            │            │                     │                     │ library  instead of  │
            │            │                     │                     │ the static library   │
            ├────────────┼─────────────────────┼─────────────────────┼──────────────────────┤
            │fPIC        │ (Boolean)           │ True                │ Compile   code   as  │
            │            │                     │                     │ position-independent │
            ├────────────┼─────────────────────┼─────────────────────┼──────────────────────┤
            │srv         │ (Boolean)           │ True                │ Enables MongoDB  SRV │
            │            │                     │                     │ URI support          │
            └────────────┴─────────────────────┴─────────────────────┴──────────────────────┘

            │with_sslopenssl,  libressl, │ openssl [1]         │ Select     a     TLS │
            │            │ windows,    darwin, │                     │ backend. Setting  to │
            │            │ False               │                     │ "False" disables TLS │
            │            │                     │                     │ support.             │
            ├────────────┼─────────────────────┼─────────────────────┼──────────────────────┤
            │with_saslsspi, cyrus, Falsesspi  on   Windows, │ Enable          SASL │
            │            │                     │ False elsewhere     │ authentication       │
            │            │                     │                     │ support              │
            ├────────────┼─────────────────────┼─────────────────────┼──────────────────────┤
            │with_snappy │ (Boolean)           │ True                │ Enable        Snappy │
            │            │                     │                     │ compression          │
            ├────────────┼─────────────────────┼─────────────────────┼──────────────────────┤
            │with_zlib   │ (Boolean)           │ True                │ Enable          Zlib │
            │            │                     │                     │ compression          │
            ├────────────┼─────────────────────┼─────────────────────┼──────────────────────┤
            │with_zstd   │ (Boolean)           │ True                │ Enable          Zstd │
            │            │                     │                     │ compression          │
            └────────────┴─────────────────────┴─────────────────────┴──────────────────────┘

       [1]  Conan will use OpenSSL as the default TLS backend, even on platforms that  ship  with
            their own TLS implementation (e.g. Windows and macOS). This behavior differs from the
            upstream default-configured libmongoc or the vcpkg  distribution  of  mongo-c-driver,
            which both default to use the TLS implementation preferred for the target platform.

   vcpkg Optional Features
       The mongo-c-driver package offered by vcpkg supports several optional features.

       SEE ALSO:The vcpkg libbson portThe vcpkg mongo-c-driver port

                              ┌────────┬──────────────────────────────────┐
                              │Feature │ Notes                            │
                              ├────────┼──────────────────────────────────┤
                              │icu     │ Installs  the ICU library, which │
                              │        │ is   necessary   for   non-ASCII │
                              │        │ usernames   and   passwords   in │
                              │        │ pre-1.25 libmongoc               │
                              ├────────┼──────────────────────────────────┤
                              │openssl │ Use OpenSSL for encryption, even │
                              │        │ on  Windows  and Apple platforms │
                              │        │ which  provide  a   native   TLS │
                              │        │ backend.                         │
                              │        │                                  │
                              │        │ If  omitted, the default will be │
                              │        │ to   use   the   preferred   TLS │
                              │        │ implementation for the system.   │
                              ├────────┼──────────────────────────────────┤
                              │snappy  │ Enable  the  Snappy  compression │
                              │        │ backend                          │
                              ├────────┼──────────────────────────────────┤
                              │zstd    │ Enable  the   Zstd   compression │
                              │        │ backend                          │
                              └────────┴──────────────────────────────────┘

   mongo-c-driver Platform Support
       This  page  documents  information  about  the  target  platforms  and toolchains that are
       supported by the mongo-c-driver libraries.

   Operating Systems
       The following operating systems are continually tested with mongo-c-driver:

                 ┌─────────────────────────────────┬──────────────────────────────────┐
                 │Operating System                 │ Notes                            │
                 └─────────────────────────────────┴──────────────────────────────────┘

                 │Debian                           │ Versions 9.2, 10.0, and 11.0     │
                 ├─────────────────────────────────┼──────────────────────────────────┤
                 │RHEL                             │ Versions 7.0, 7.1, 8.1, 8.2, and │
                 │                                 │ 8.3.   RHEL   derivatives  (e.g. │
                 │                                 │ CentOS, Rocky Linux,  AlmaLinux) │
                 │                                 │ of  the same release version are │
                 │                                 │ supported.   Fedora   is    also │
                 │                                 │ supported,  but  not continually │
                 │                                 │ tested.                          │
                 ├─────────────────────────────────┼──────────────────────────────────┤
                 │Ubuntu                           │ Versions   16.04,   18.04,   and │
                 │                                 │ 20.04. Subsequent minor releases │
                 │                                 │ are also supported. Ubuntu 22.04 │
                 │                                 │ and  newer  is  not  yet tested. │
                 │                                 │ Ubuntu  derivatives   based   on │
                 │                                 │ supported  Ubuntu  versions  are │
                 │                                 │ also supported.                  │
                 ├─────────────────────────────────┼──────────────────────────────────┤
                 │Arch Linux                       │                                  │
                 ├─────────────────────────────────┼──────────────────────────────────┤
                 │macOS                            │ Version 11.0                     │
                 ├─────────────────────────────────┼──────────────────────────────────┤
                 │Windows Server 2008 and  Windows │ Windows  variants  of  the  same │
                 │Server 2016                      │ generation are supported         │
                 └─────────────────────────────────┴──────────────────────────────────┘

   Compilers
       The following compilers are continually tested for mongo-c-driver:

                    ┌────────────────────────────┬──────────────────────────────────┐
                    │Compiler                    │ Notes                            │
                    ├────────────────────────────┼──────────────────────────────────┤
                    │Clang                       │ Versions  3.7,  3.8,  and   6.0. │
                    │                            │ Newer    versions    are    also │
                    │                            │ supported,  as   well   as   the │
                    │                            │ corresponding     Apple    Clang │
                    │                            │ releases.                        │
                    ├────────────────────────────┼──────────────────────────────────┤
                    │GCC                         │ Versions  4.8,  5.4,  6.3,  7.5, │
                    │                            │ 8.2,  8.3,  9.4,  and  10.2. The │
                    │                            │ MinGW-w64 GCC is also tested and │
                    │                            │ supported.                       │
                    ├────────────────────────────┼──────────────────────────────────┤
                    │Microsoft Visual C++ (MSVC) │ Tested  with  MSVC  12.x (Visual │
                    │                            │ Studio   2013),   14.x   (Visual │
                    │                            │ Studio  2015),  and 15.x (Visual │
                    │                            │ Studio   2017).    Newer    MSVC │
                    │                            │ versions  are  supported but not │
                    │                            │ yet tested.                      │
                    └────────────────────────────┴──────────────────────────────────┘

   Architectures
       The following CPU architectures are continually tested for mongo-c-driver:

                        ┌────────────────────┬──────────────────────────────────┐
                        │Architecture        │ Notes                            │
                        ├────────────────────┼──────────────────────────────────┤
                        │x86 (32-bit)        │ Only tested on Windows           │
                        ├────────────────────┼──────────────────────────────────┤
                        │x86_64 (64-bit x86) │ Tested  on  Linux,  macOS,   and │
                        │                    │ Windows                          │
                        ├────────────────────┼──────────────────────────────────┤
                        │ARM / aarch64       │ Tested on macOS and Linux        │
                        ├────────────────────┼──────────────────────────────────┤
                        │Power8 (ppc64le)    │ Only tested on Linux             │
                        └────────────────────┴──────────────────────────────────┘

                        │zSeries (s390x)     │ Only tested on Linux             │
                        └────────────────────┴──────────────────────────────────┘

   Others
       Other platforms and toolchains are not tested, but similar versions of the above platforms
       should work. If you encounter a platform or toolchain that you expect  to  work  and  find
       that  it  does not, please open an issue describing the problem, and/or open a GitHub Pull
       Request to fix it.

       Simple pull requests to fix unsupported platforms are welcome, but will be considered on a
       case-by-case  basis.  The  acceptance  of  a  pull  request  to  fix  the  libraries on an
       unsupported platform does not imply full support of that platform.

   Tutorial
       This guide offers a brief introduction to the MongoDB C Driver.

       For more information on the C API, please refer to the API Reference.

   Installing
       For detailed instructions on installing the MongoDB C Driver  on  a  particular  platform,
       please see the installation guide.

   Starting MongoDB
       To  run  the examples in this tutorial, MongoDB must be installed and running on localhost
       on the default port, 27017. To check if it is up and  running,  connect  to  it  with  the
       MongoDB shell.

          $ mongosh --host localhost --port 27017 --quiet
          Enterprise rs0 [direct: primary] test> db.version()
          7.0.0
          >

   Include and link libmongoc in your C program
   Include mongoc.h
       All  libmongoc's  functions  and  types  are  available in one header file. Simply include
       mongoc/mongoc.h:

          #include <mongoc/mongoc.h>

   CMake
       The libmongoc installation includes a CMake config-file package, so you  can  use  CMake's
       find_package command to import libmongoc's CMake target and link to libmongoc (as a shared
       library):

       CMakeLists.txt

          # Specify the minimum version you require.
          find_package (mongoc-1.0 1.7 REQUIRED)

          # The "hello_mongoc.c" sample program is shared among four tests.
          add_executable (hello_mongoc ../../hello_mongoc.c)
          target_link_libraries (hello_mongoc PRIVATE mongo::mongoc_shared)

       You can also use libmongoc as a static library instead: Use the mongo::mongoc_static CMake
       target:

          # Specify the minimum version you require.
          find_package (mongoc-1.0 1.7 REQUIRED)

          # The "hello_mongoc.c" sample program is shared among four tests.
          add_executable (hello_mongoc ../../hello_mongoc.c)
          target_link_libraries (hello_mongoc PRIVATE mongo::mongoc_static)

   pkg-config
       If  you're  not  using CMake, use pkg-config on the command line to set header and library
       paths:

          gcc -o hello_mongoc hello_mongoc.c $(pkg-config --libs --cflags libmongoc-1.0)

       Or to statically link to libmongoc:

          gcc -o hello_mongoc hello_mongoc.c $(pkg-config --libs --cflags libmongoc-static-1.0)

   Specifying header and include paths manually
       If you aren't using CMake or pkg-config, paths and libraries can be managed manually.

          $ gcc -o hello_mongoc hello_mongoc.c \
              -I/usr/local/include/libbson-1.0 -I/usr/local/include/libmongoc-1.0 \
              -lmongoc-1.0 -lbson-1.0
          $ ./hello_mongoc
          { "ok" : 1.000000 }

       For Windows users, the code can be compiled and run with  the  following  commands.  (This
       assumes  that  the  MongoDB  C  Driver has been installed to C:\mongo-c-driver; change the
       include directory as needed.)

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 hello_mongoc.c
          C:\> hello_mongoc
          { "ok" : 1.000000 }

   Use libmongoc in a Microsoft Visual Studio Project
       See the libmongoc and Visual Studio guide.

   Making a Connection
       Access MongoDB with a mongoc_client_t. It transparently connects  to  standalone  servers,
       replica  sets  and  sharded  clusters  on  demand.  To perform operations on a database or
       collection,  create  a  mongoc_database_t   or   mongoc_collection_t   struct   from   the
       mongoc_client_t.

       At  the  start of an application, call mongoc_init() before any other libmongoc functions.
       At the end, call the appropriate destroy function for each collection, database, or client
       handle,  in  reverse  order  from  how they were constructed. Call mongoc_cleanup() before
       exiting.

       The example below establishes a connection to a standalone server on localhost,  registers
       the client application as "connect-example," and performs a simple command.

       More  information  about  database  operations  can  be  found  in the CRUD Operations and
       Executing Commands sections. Examples of connecting to replica sets and  sharded  clusters
       can  be  found in the Advanced Connections page, while examples of data compression can be
       found in the Data Compression page.

       hello_mongoc.c

          #include <mongoc/mongoc.h>

          int
          main (int argc, char *argv[])
          {
             const char *uri_string = "mongodb://localhost:27017";
             mongoc_uri_t *uri;
             mongoc_client_t *client;
             mongoc_database_t *database;
             mongoc_collection_t *collection;
             bson_t *command, reply, *insert;
             bson_error_t error;
             char *str;
             bool retval;

             /*
              * Required to initialize libmongoc's internals
              */
             mongoc_init ();

             /*
              * Optionally get MongoDB URI from command line
              */
             if (argc > 1) {
                uri_string = argv[1];
             }

             /*
              * Safely create a MongoDB URI object from the given string
              */
             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             /*
              * Create a new client instance
              */
             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             /*
              * Register the application name so we can track it in the profile logs
              * on the server. This can also be done from the URI (see other examples).
              */
             mongoc_client_set_appname (client, "connect-example");

             /*
              * Get a handle on the database "db_name" and collection "coll_name"
              */
             database = mongoc_client_get_database (client, "db_name");
             collection = mongoc_client_get_collection (client, "db_name", "coll_name");

             /*
              * Do work. This example pings the database, prints the result as JSON and
              * performs an insert
              */
             command = BCON_NEW ("ping", BCON_INT32 (1));

             retval = mongoc_client_command_simple (
                client, "admin", command, NULL, &reply, &error);

             if (!retval) {
                fprintf (stderr, "%s\n", error.message);
                return EXIT_FAILURE;
             }

             str = bson_as_json (&reply, NULL);
             printf ("%s\n", str);

             insert = BCON_NEW ("hello", BCON_UTF8 ("world"));

             if (!mongoc_collection_insert_one (collection, insert, NULL, NULL, &error)) {
                fprintf (stderr, "%s\n", error.message);
             }

             bson_destroy (insert);
             bson_destroy (&reply);
             bson_destroy (command);
             bson_free (str);

             /*
              * Release our handles and clean up libmongoc
              */
             mongoc_collection_destroy (collection);
             mongoc_database_destroy (database);
             mongoc_uri_destroy (uri);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

   Creating BSON Documents
       Documents are stored in MongoDB's data format, BSON. The C driver uses libbson  to  create
       BSON documents. There are several ways to construct them: appending key-value pairs, using
       BCON, or parsing JSON.

   Appending BSON
       A BSON document, represented as a bson_t in code, can be constructed one field at  a  time
       using libbson's append functions.

       For example, to create a document like this:

          {
             born : ISODate("1906-12-09"),
             died : ISODate("1992-01-01"),
             name : {
                first : "Grace",
                last : "Hopper"
             },
             languages : [ "MATH-MATIC", "FLOW-MATIC", "COBOL" ],
             degrees: [ { degree: "BA", school: "Vassar" }, { degree: "PhD", school: "Yale" } ]
          }

       Use the following code:

          #include <bson/bson.h>

          int
          main (int argc, char *argv[])
          {
             struct tm born = {0};
             struct tm died = {0};
             const char *lang_names[] = {"MATH-MATIC", "FLOW-MATIC", "COBOL"};
             const char *schools[] = {"Vassar", "Yale"};
             const char *degrees[] = {"BA", "PhD"};
             uint32_t i;
             bson_t *document;
             bson_t child;
             bson_array_builder_t *bab;
             char *str;

             document = bson_new ();

             /*
              * Append { "born" : ISODate("1906-12-09") } to the document.
              * Passing -1 for the length argument tells libbson to calculate the
              * string length.
              */
             born.tm_year = 6; /* years are 1900-based */
             born.tm_mon = 11; /* months are 0-based */
             born.tm_mday = 9;
             bson_append_date_time (document, "born", -1, mktime (&born) * 1000);

             /*
              * Append { "died" : ISODate("1992-01-01") } to the document.
              */
             died.tm_year = 92;
             died.tm_mon = 0;
             died.tm_mday = 1;

             /*
              * For convenience, this macro passes length -1 by default.
              */
             BSON_APPEND_DATE_TIME (document, "died", mktime (&died) * 1000);

             /*
              * Append a subdocument.
              */
             BSON_APPEND_DOCUMENT_BEGIN (document, "name", &child);
             BSON_APPEND_UTF8 (&child, "first", "Grace");
             BSON_APPEND_UTF8 (&child, "last", "Hopper");
             bson_append_document_end (document, &child);

             /*
              * Append array of strings. Generate keys "0", "1", "2".
              */
             BSON_APPEND_ARRAY_BUILDER_BEGIN (document, "languages", &bab);
             for (i = 0; i < sizeof lang_names / sizeof (char *); ++i) {
                bson_array_builder_append_utf8 (bab, lang_names[i], -1);
             }
             bson_append_array_builder_end (document, bab);

             /*
              * Array of subdocuments:
              *    degrees: [ { degree: "BA", school: "Vassar" }, ... ]
              */
             BSON_APPEND_ARRAY_BUILDER_BEGIN (document, "degrees", &bab);
             for (i = 0; i < sizeof degrees / sizeof (char *); ++i) {
                bson_array_builder_append_document_begin (bab, &child);
                BSON_APPEND_UTF8 (&child, "degree", degrees[i]);
                BSON_APPEND_UTF8 (&child, "school", schools[i]);
                bson_array_builder_append_document_end (bab, &child);
             }
             bson_append_array_builder_end (document, bab);

             /*
              * Print the document as a JSON string.
              */
             str = bson_as_canonical_extended_json (document, NULL);
             printf ("%s\n", str);
             bson_free (str);

             /*
              * Clean up allocated bson documents.
              */
             bson_destroy (document);
             return 0;
          }

       See the libbson documentation for all of the types that can be appended to a bson_t.

   Using BCON
       BSON  C  Object  Notation,  BCON  for  short,  is  an alternative way of constructing BSON
       documents in a manner closer to the intended format. It has less type-safety  than  BSON's
       append functions but results in less code.

          #include <bson/bson.h>

          int
          main (int   argc,
                char *argv[])
          {
             struct tm born = { 0 };
             struct tm died = { 0 };
             bson_t   *document;
             char     *str;

             born.tm_year = 6;
             born.tm_mon = 11;
             born.tm_mday = 9;

             died.tm_year = 92;
             died.tm_mon = 0;
             died.tm_mday = 1;

             document = BCON_NEW (
                "born", BCON_DATE_TIME (mktime (&born) * 1000),
                "died", BCON_DATE_TIME (mktime (&died) * 1000),
                "name", "{",
                "first", BCON_UTF8 ("Grace"),
                "last", BCON_UTF8 ("Hopper"),
                "}",
                "languages", "[",
                BCON_UTF8 ("MATH-MATIC"),
                BCON_UTF8 ("FLOW-MATIC"),
                BCON_UTF8 ("COBOL"),
                "]",
                "degrees", "[",
                "{", "degree", BCON_UTF8 ("BA"), "school", BCON_UTF8 ("Vassar"), "}",
                "{", "degree", BCON_UTF8 ("PhD"), "school", BCON_UTF8 ("Yale"), "}",
                "]");

             /*
              * Print the document as a JSON string.
              */
             str = bson_as_canonical_extended_json (document, NULL);
             printf ("%s\n", str);
             bson_free (str);

             /*
              * Clean up allocated bson documents.
              */
             bson_destroy (document);
             return 0;
          }

       Notice that BCON can create arrays, subdocuments and arbitrary fields.

   Creating BSON from JSON
       For single documents, BSON can be created from JSON strings via bson_new_from_json.

          #include <bson/bson.h>

          int
          main (int   argc,
                char *argv[])
          {
             bson_error_t error;
             bson_t      *bson;
             char        *string;

             const char *json = "{\"name\": {\"first\":\"Grace\", \"last\":\"Hopper\"}}";
             bson = bson_new_from_json ((const uint8_t *)json, -1, &error);

             if (!bson) {
                fprintf (stderr, "%s\n", error.message);
                return EXIT_FAILURE;
             }

             string = bson_as_canonical_extended_json (bson, NULL);
             printf ("%s\n", string);
             bson_free (string);

             return 0;
          }

       To initialize BSON from a sequence of JSON documents, use bson_json_reader_t.

   Basic CRUD Operations
       This section demonstrates the basics of using the C Driver to interact with MongoDB.

   Inserting a Document
       To  insert documents into a collection, first obtain a handle to a mongoc_collection_t via
       a mongoc_client_t. Then, use mongoc_collection_insert_one() to add BSON documents  to  the
       collection. This example inserts into the database "mydb" and collection "mycoll".

       When  finished,  ensure  that  allocated  structures  are  freed by using their respective
       destroy functions.

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          int
          main (int   argc,
                char *argv[])
          {
              mongoc_client_t *client;
              mongoc_collection_t *collection;
              bson_error_t error;
              bson_oid_t oid;
              bson_t *doc;

              mongoc_init ();

              client = mongoc_client_new ("mongodb://localhost:27017/?appname=insert-example");
              collection = mongoc_client_get_collection (client, "mydb", "mycoll");

              doc = bson_new ();
              bson_oid_init (&oid, NULL);
              BSON_APPEND_OID (doc, "_id", &oid);
              BSON_APPEND_UTF8 (doc, "hello", "world");

              if (!mongoc_collection_insert_one (
                     collection, doc, NULL, NULL, &error)) {
                  fprintf (stderr, "%s\n", error.message);
              }

              bson_destroy (doc);
              mongoc_collection_destroy (collection);
              mongoc_client_destroy (client);
              mongoc_cleanup ();

              return 0;
          }

       Compile the code and run it:

          $ gcc -o insert insert.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./insert

       On Windows:

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 insert.c
          C:\> insert

       To verify that the insert succeeded, connect with the MongoDB shell.

          $ mongo
          MongoDB shell version: 3.0.6
          connecting to: test
          > use mydb
          switched to db mydb
          > db.mycoll.find()
          { "_id" : ObjectId("55ef43766cb5f36a3bae6ee4"), "hello" : "world" }
          >

   Finding a Document
       To   query   a   MongoDB   collection   with   the   C   driver,    use    the    function
       mongoc_collection_find_with_opts().  This  returns a cursor to the matching documents. The
       following examples iterate through the result cursors and print the matches to  stdout  as
       JSON strings.

       Use a document as a query specifier; for example,

          { "color" : "red" }

       will  match any document with a field named "color" with value "red". An empty document {}
       can be used to match all documents.

       This first example uses an empty query specifier to find all  documents  in  the  database
       "mydb" and collection "mycoll".

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             mongoc_cursor_t *cursor;
             const bson_t *doc;
             bson_t *query;
             char *str;

             mongoc_init ();

             client =
                mongoc_client_new ("mongodb://localhost:27017/?appname=find-example");
             collection = mongoc_client_get_collection (client, "mydb", "mycoll");
             query = bson_new ();
             cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_canonical_extended_json (doc, NULL);
                printf ("%s\n", str);
                bson_free (str);
             }

             bson_destroy (query);
             mongoc_cursor_destroy (cursor);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return 0;
          }

       Compile the code and run it:

          $ gcc -o find find.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./find
          { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

       On Windows:

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 find.c
          C:\> find
          { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

       To  look  for  a  specific document, add a specifier to query. This example adds a call to
       BSON_APPEND_UTF8() to look for all documents matching {"hello" : "world"}.

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             mongoc_cursor_t *cursor;
             const bson_t *doc;
             bson_t *query;
             char *str;

             mongoc_init ();

             client = mongoc_client_new (
                "mongodb://localhost:27017/?appname=find-specific-example");
             collection = mongoc_client_get_collection (client, "mydb", "mycoll");
             query = bson_new ();
             BSON_APPEND_UTF8 (query, "hello", "world");

             cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_canonical_extended_json (doc, NULL);
                printf ("%s\n", str);
                bson_free (str);
             }

             bson_destroy (query);
             mongoc_cursor_destroy (cursor);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return 0;
          }

          $ gcc -o find-specific find-specific.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./find-specific
          { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 find-specific.c
          C:\> find-specific
          { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

   Updating a Document
       This code snippet gives an example of using mongoc_collection_update_one() to  update  the
       fields of a document.

       Using  the  "mydb"  database,  the  following example inserts an example document into the
       "mycoll" collection. Then, using its _id field, the document  is  updated  with  different
       values and a new field.

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_collection_t *collection;
             mongoc_client_t *client;
             bson_error_t error;
             bson_oid_t oid;
             bson_t *doc = NULL;
             bson_t *update = NULL;
             bson_t *query = NULL;

             mongoc_init ();

             client =
                mongoc_client_new ("mongodb://localhost:27017/?appname=update-example");
             collection = mongoc_client_get_collection (client, "mydb", "mycoll");

             bson_oid_init (&oid, NULL);
             doc = BCON_NEW ("_id", BCON_OID (&oid), "key", BCON_UTF8 ("old_value"));

             if (!mongoc_collection_insert_one (collection, doc, NULL, &error)) {
                fprintf (stderr, "%s\n", error.message);
                goto fail;
             }

             query = BCON_NEW ("_id", BCON_OID (&oid));
             update = BCON_NEW ("$set",
                                "{",
                                "key",
                                BCON_UTF8 ("new_value"),
                                "updated",
                                BCON_BOOL (true),
                                "}");

             if (!mongoc_collection_update_one (
                    collection, query, update, NULL, NULL, &error)) {
                fprintf (stderr, "%s\n", error.message);
                goto fail;
             }

          fail:
             if (doc)
                bson_destroy (doc);
             if (query)
                bson_destroy (query);
             if (update)
                bson_destroy (update);

             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return 0;
          }

       Compile the code and run it:

          $ gcc -o update update.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./update

       On Windows:

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 update.c
          C:\> update
          { "_id" : { "$oid" : "55ef43766cb5f36a3bae6ee4" }, "hello" : "world" }

       To verify that the update succeeded, connect with the MongoDB shell.

          $ mongo
          MongoDB shell version: 3.0.6
          connecting to: test
          > use mydb
          switched to db mydb
          > db.mycoll.find({"updated" : true})
          { "_id" : ObjectId("55ef549236fe322f9490e17b"), "updated" : true, "key" : "new_value" }
          >

   Deleting a Document
       This example illustrates the use of mongoc_collection_delete_one() to delete a document.

       The  following  code  inserts  a  sample  document into the database "mydb" and collection
       "mycoll". Then, it deletes all documents matching {"hello" : "world"}.

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             bson_error_t error;
             bson_oid_t oid;
             bson_t *doc;

             mongoc_init ();

             client =
                mongoc_client_new ("mongodb://localhost:27017/?appname=delete-example");
             collection = mongoc_client_get_collection (client, "test", "test");

             doc = bson_new ();
             bson_oid_init (&oid, NULL);
             BSON_APPEND_OID (doc, "_id", &oid);
             BSON_APPEND_UTF8 (doc, "hello", "world");

             if (!mongoc_collection_insert_one (collection, doc, NULL, &error)) {
                fprintf (stderr, "Insert failed: %s\n", error.message);
             }

             bson_destroy (doc);

             doc = bson_new ();
             BSON_APPEND_OID (doc, "_id", &oid);

             if (!mongoc_collection_delete_one (
                    collection, doc, NULL, NULL, &error)) {
                fprintf (stderr, "Delete failed: %s\n", error.message);
             }

             bson_destroy (doc);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return 0;
          }

       Compile the code and run it:

          $ gcc -o delete delete.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./delete

       On Windows:

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 delete.c
          C:\> delete

       Use the MongoDB shell to prove that the documents have been removed successfully.

          $ mongo
          MongoDB shell version: 3.0.6
          connecting to: test
          > use mydb
          switched to db mydb
          > db.mycoll.count({"hello" : "world"})
          0
          >

   Counting Documents
       Counting the number of documents in a MongoDB collection is similar to performing  a  find
       operation. This example counts the number of documents matching {"hello" : "world"} in the
       database "mydb" and collection "mycoll".

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             bson_error_t error;
             bson_t *doc;
             int64_t count;

             mongoc_init ();

             client =
                mongoc_client_new ("mongodb://localhost:27017/?appname=count-example");
             collection = mongoc_client_get_collection (client, "mydb", "mycoll");
             doc = bson_new_from_json (
                (const uint8_t *) "{\"hello\" : \"world\"}", -1, &error);

             count = mongoc_collection_count (
                collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error);

             if (count < 0) {
                fprintf (stderr, "%s\n", error.message);
             } else {
                printf ("%" PRId64 "\n", count);
             }

             bson_destroy (doc);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return 0;
          }

       Compile the code and run it:

          $ gcc -o count count.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./count
          1

       On Windows:

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 count.c
          C:\> count
          1

   Executing Commands
       The driver provides helper functions for executing MongoDB commands  on  client,  database
       and  collection  structures.  The  _simple  variants return booleans indicating success or
       failure.

       This example executes the ping command against the database "mydb".

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;
             bson_error_t error;
             bson_t *command;
             bson_t reply;
             char *str;

             mongoc_init ();

             client = mongoc_client_new (
                "mongodb://localhost:27017/?appname=executing-example");

             command = BCON_NEW ("ping", BCON_INT32 (1));
             if (mongoc_client_command_simple (
                    client, "mydb", command, NULL, &reply, &error)) {
                str = bson_as_canonical_extended_json (&reply, NULL);
                printf ("%s\n", str);
                bson_free (str);
             } else {
                fprintf (stderr, "Failed to run command: %s\n", error.message);
             }

             bson_destroy (command);
             bson_destroy (&reply);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return 0;
          }

       Compile the code and run it:

          $ gcc -o executing executing.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./executing
          { "ok" : { "$numberDouble" : "1.0" }, "$clusterTime" : { "clusterTime" : { "$timestamp" : { "t" : 1682609211, "i" : 1 } }, "signature" : { "hash" : { "$binary" : { "base64" : "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType" : "00" } }, "keyId" : { "$numberLong" : "0" } } }, "operationTime" : { "$timestamp" : { "t" : 1682609211, "i" : 1 } } }

       On Windows:

          C:\> cl.exe /IC:\mongo-c-driver\include\libbson-1.0 /IC:\mongo-c-driver\include\libmongoc-1.0 executing.c
          C:\> executing
          { "ok" : { "$numberDouble" : "1.0" }, "$clusterTime" : { "clusterTime" : { "$timestamp" : { "t" : 1682609211, "i" : 1 } }, "signature" : { "hash" : { "$binary" : { "base64" : "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType" : "00" } }, "keyId" : { "$numberLong" : "0" } } }, "operationTime" : { "$timestamp" : { "t" : 1682609211, "i" : 1 } } }

   Threading
       The MongoDB C Driver is thread-unaware in the vast majority of its operations. This  means
       it is up to the programmer to guarantee thread-safety.

       However,  mongoc_client_pool_t  is thread-safe and is used to fetch a mongoc_client_t in a
       thread-safe manner. After retrieving a client from the pool, the client  structure  should
       be  considered owned by the calling thread. When the thread is finished, the client should
       be placed back into the pool.

       example-pool.c

          /* gcc example-pool.c -o example-pool $(pkg-config --cflags --libs
           * libmongoc-1.0) */

          /* ./example-pool [CONNECTION_STRING] */

          #include <mongoc/mongoc.h>
          #include <pthread.h>
          #include <stdio.h>

          static pthread_mutex_t mutex;
          static bool in_shutdown = false;

          static void *
          worker (void *data)
          {
             mongoc_client_pool_t *pool = data;
             mongoc_client_t *client;
             bson_t ping = BSON_INITIALIZER;
             bson_error_t error;
             bool r;

             BSON_APPEND_INT32 (&ping, "ping", 1);

             while (true) {
                client = mongoc_client_pool_pop (pool);
                /* Do something with client. If you are writing an HTTP server, you
                 * probably only want to hold onto the client for the portion of the
                 * request performing database queries.
                 */
                r = mongoc_client_command_simple (
                   client, "admin", &ping, NULL, NULL, &error);

                if (!r) {
                   fprintf (stderr, "%s\n", error.message);
                }

                mongoc_client_pool_push (pool, client);

                pthread_mutex_lock (&mutex);
                if (in_shutdown || !r) {
                   pthread_mutex_unlock (&mutex);
                   break;
                }

                pthread_mutex_unlock (&mutex);
             }

             bson_destroy (&ping);
             return NULL;
          }

          int
          main (int argc, char *argv[])
          {
             const char *uri_string = "mongodb://127.0.0.1/?appname=pool-example";
             mongoc_uri_t *uri;
             bson_error_t error;
             mongoc_client_pool_t *pool;
             pthread_t threads[10];
             unsigned i;
             void *ret;

             pthread_mutex_init (&mutex, NULL);
             mongoc_init ();

             if (argc > 1) {
                uri_string = argv[1];
             }

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             pool = mongoc_client_pool_new (uri);
             mongoc_client_pool_set_error_api (pool, 2);

             for (i = 0; i < 10; i++) {
                pthread_create (&threads[i], NULL, worker, pool);
             }

             sleep (10);
             pthread_mutex_lock (&mutex);
             in_shutdown = true;
             pthread_mutex_unlock (&mutex);

             for (i = 0; i < 10; i++) {
                pthread_join (threads[i], &ret);
             }

             mongoc_client_pool_destroy (pool);
             mongoc_uri_destroy (uri);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

   Next Steps
       To find information on advanced topics, browse the rest of  the  C  driver  guide  or  the
       official MongoDB documentation.

       For  help with common issues, consult the Troubleshooting page. To report a bug or request
       a new feature, follow these instructions.

   Authentication
       This guide covers the use of authentication options with the MongoDB C Driver. Ensure that
       the  MongoDB  server  is  also  properly  configured  for  authentication  before making a
       connection. For more information, see the MongoDB security documentation.

       The MongoDB C driver supports several authentication mechanisms through the use of MongoDB
       connection URIs.

       By  default, if a username and password are provided as part of the connection string (and
       an  optional  authentication  database),  they  are  used  to  connect  via  the   default
       authentication mechanism of the server.

       To  select  a  specific  authentication  mechanism other than the default, see the list of
       supported mechanism below.

          mongoc_client_t *client = mongoc_client_new ("mongodb://user:password@localhost/?authSource=mydb");

       Currently supported values for the authMechanism connection string option are:

       • SCRAM-SHA-1MONGODB-CR (deprecated)GSSAPIPLAINX509MONGODB-AWS

   Basic Authentication (SCRAM-SHA-256)
       MongoDB 4.0 introduces support for authenticating using the SCRAM protocol with  the  more
       secure  SHA-256 hash described in RFC 7677. Using this authentication mechanism means that
       the password is never actually sent over  the  wire  when  authenticating,  but  rather  a
       computed  proof  that the client password is the same as the password the server knows. In
       MongoDB 4.0, the C driver can determine the correct default authentication  mechanism  for
       users with stored SCRAM-SHA-1 and SCRAM-SHA-256 credentials:

          mongoc_client_t *client =  mongoc_client_new ("mongodb://user:password@localhost/?authSource=mydb");
          /* the correct authMechanism is negotiated between the driver and server. */

       Alternatively, SCRAM-SHA-256 can be explicitly specified as an authMechanism.

          mongoc_client_t *client =  mongoc_client_new ("mongodb://user:password@localhost/?authMechanism=SCRAM-SHA-256&authSource=mydb");

   Basic Authentication (SCRAM-SHA-1)
       The  default  authentication mechanism before MongoDB 4.0 is SCRAM-SHA-1 (RFC 5802). Using
       this authentication mechanism means that the password is never actually sent over the wire
       when  authenticating,  but rather a computed proof that the client password is the same as
       the password the server knows.

          mongoc_client_t *client = mongoc_client_new ("mongodb://user:password@localhost/?authMechanism=SCRAM-SHA-1&authSource=mydb");

       NOTE:
          SCRAM-SHA-1 authenticates against the admin database by default. If the user is created
          in another database, then specifying the authSource is required.

   Legacy Authentication (MONGODB-CR)
       The  MONGODB-CR  authMechanism  is  deprecated and will no longer function in MongoDB 4.0.
       Instead, specify no authMechanism and the driver  will  use  an  authentication  mechanism
       compatible with your server.

   GSSAPI (Kerberos) Authentication
       NOTE:
          On  UNIX-like  environments,  Kerberos  support  requires  compiling the driver against
          cyrus-sasl.

          On Windows, Kerberos support requires compiling the driver against Windows Native  SSPI
          or cyrus-sasl. The default configuration of the driver will use Windows Native SSPI.

          To modify the default configuration, use the cmake option ENABLE_SASL.

       GSSAPI  (Kerberos)  authentication  is  available in the Enterprise Edition of MongoDB. To
       authenticate using GSSAPI, the MongoDB C driver must be installed with SASL support.

       On UNIX-like environments, run the kinit command before using the following authentication
       methods:

          $ kinit mongodbuser@EXAMPLE.COM
          mongodbuser@EXAMPLE.COM's Password:
          $ klistCredentials cache: FILE:/tmp/krb5cc_1000
                  Principal: mongodbuser@EXAMPLE.COM

            Issued                Expires               Principal
          Feb  9 13:48:51 2013  Feb  9 23:48:51 2013  krbtgt/EXAMPLE.COM@EXAMPLE.COM

       Now authenticate using the MongoDB URI. GSSAPI authenticates against the $external virtual
       database, so a database does not need to be specified in the URI. Note that  the  Kerberos
       principal must be URL-encoded:

          mongoc_client_t *client;

          client = mongoc_client_new ("mongodb://mongodbuser%40EXAMPLE.COM@mongo-server.example.com/?authMechanism=GSSAPI");

       NOTE:
          GSSAPI  authenticates  against  the  $external  database,  so specifying the authSource
          database is not required.

       The driver supports these GSSAPI properties:

       • CANONICALIZE_HOST_NAME: This might be required with Cyrus-SASL  when  the  hosts  report
         different hostnames than what is used in the Kerberos database. The default is "false".

       • SERVICE_NAME: Use a different service name than the default, "mongodb".

       Set properties in the URL:

          mongoc_client_t *client;

          client = mongoc_client_new ("mongodb://mongodbuser%40EXAMPLE.COM@mongo-server.example.com/?authMechanism=GSSAPI&"
                                      "authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true");

       If  you encounter errors such as Invalid net address, check if the application is behind a
       NAT (Network Address Translation) firewall. If so, create a ticket that  uses  forwardable
       and addressless Kerberos tickets. This can be done by passing -f -A to kinit.

          $ kinit -f -A mongodbuser@EXAMPLE.COM

   SASL Plain Authentication
       NOTE:
          The  MongoDB  C  Driver  must  be compiled with SASL support in order to use SASL PLAIN
          authentication.

       MongoDB Enterprise Edition supports the SASL  PLAIN  authentication  mechanism,  initially
       intended  for  delegating authentication to an LDAP server. Using the SASL PLAIN mechanism
       is very similar to the challenge response mechanism with  usernames  and  passwords.  This
       authentication mechanism uses the $external virtual database for LDAP support:

       NOTE:
          SASL  PLAIN  is  a  clear-text  authentication mechanism. It is strongly recommended to
          connect to  MongoDB  using  TLS  with  certificate  validation  when  using  the  PLAIN
          mechanism.

          mongoc_client_t *client;

          client = mongoc_client_new ("mongodb://user:password@example.com/?authMechanism=PLAIN");

       PLAIN  authenticates against the $external database, so specifying the authSource database
       is not required.

   X.509 Certificate Authentication
       NOTE:
          The MongoDB C Driver must  be  compiled  with  TLS  support  for  X.509  authentication
          support. Once this is done, start a server with the following options:

              $ mongod --tlsMode requireTLS --tlsCertificateKeyFile server.pem --tlsCAFile ca.pem

       The MONGODB-X509 mechanism authenticates a username derived from the distinguished subject
       name of the X.509 certificate  presented  by  the  driver  during  TLS  negotiation.  This
       authentication method requires the use of TLS connections with certificate validation.

          mongoc_client_t *client;
          mongoc_ssl_opt_t ssl_opts = { 0 };

          ssl_opts.pem_file = "mycert.pem";
          ssl_opts.pem_pwd = "mycertpassword";
          ssl_opts.ca_file = "myca.pem";
          ssl_opts.ca_dir = "trust_dir";
          ssl_opts.weak_cert_validation = false;

          client = mongoc_client_new ("mongodb://x509_derived_username@localhost/?authMechanism=MONGODB-X509");
          mongoc_client_set_ssl_opts (client, &ssl_opts);

       MONGODB-X509  authenticates  against  the $external database, so specifying the authSource
       database is not required. For more  information  on  the  x509_derived_username,  see  the
       MongoDB server x.509 tutorial.

       NOTE:
          The  MongoDB  C Driver will attempt to determine the x509 derived username when none is
          provided, and as of MongoDB 3.4 providing the username is not required at all.

   Authentication via AWS IAM
       The MONGODB-AWS mechanism authenticates to MongoDB servers with  credentials  provided  by
       AWS Identity and Access Management (IAM).

       To  authenticate,  create  a  user  with  an  associated Amazon Resource Name (ARN) on the
       $external database, and specify the MONGODB-AWS authMechanism in the URI.

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost/?authMechanism=MONGODB-AWS");

       Since MONGODB-AWS always authenticates against the $external database, so  specifying  the
       authSource database is not required.

       Credentials include the access key id, secret access key, and optional session token. They
       may be obtained from the following ways.

   AWS credentials via URI
       Credentials may be passed directly in the URI as username/password.

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://<access key id>:<secret access key>localhost/?authMechanism=MONGODB-AWS");

       This may include a session token passed with authMechanismProperties.

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://<access key id>:<secret access key>localhost/?authMechanism=MONGODB-AWS&authMechanismProperties=AWS_SESSION_TOKEN:<token>");

   AWS credentials via environment
       If credentials are not passed through the URI, libmongoc  will  check  for  the  following
       environment variables.

       • AWS_ACCESS_KEY_ID

       • AWS_SECRET_ACCESS_KEY

       • AWS_SESSION_TOKEN (optional)

   AWS Credentials via ECS
       If  credentials  are  not  passed in the URI or with environment variables, libmongoc will
       check if the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI is  set,  and  if
       so,  attempt  to  retrieve  temporary credentials from the ECS task metadata by querying a
       link local address.

   AWS Credentials via EC2
       If credentials are  not  passed  in  the  URI  or  with  environment  variables,  and  the
       environment  variable  AWS_CONTAINER_CREDENTIALS_RELATIVE_URI  is  not set, libmongoc will
       attempt to retrieve temporary credentials from the EC2 machine metadata by  querying  link
       local addresses.

   Basic Troubleshooting
   Troubleshooting Checklist
       The following is a short list of things to check when you have a problem.

       • Did you call mongoc_init() in main()? If not, you will likely see a segfault.

       • Have you leaked any clients or cursors as can be found with mongoc-stat <PID>?

       • Have packets been delivered to the server? See egress bytes from mongoc-stat <PID>.

       • Does ASAN show any leaks? Ensure you call mongoc_cleanup() at the end of your process to
         cleanup lingering allocations from the MongoDB C driver.

       • If compiling your own copy  of  MongoDB  C  Driver,  consider  using  the  cmake  option
         -DENABLE_TRACING=ON  to  enable  function  tracing  and  hex dumps of network packets to
         STDERR and STDOUT.

   Performance Counters
       The MongoDB C Driver comes with an optional and unique  feature  to  help  developers  and
       sysadmins  troubleshoot  problems  in  production.  Performance counters are available for
       each process using the C Driver.  If available, the counters can be  accessed  outside  of
       the  application  process  via  a  shared  memory segment.  The counters may be used graph
       statistics about your application process easily from tools like  Munin  or  Nagios.   For
       example,  the  command  watch --interval=0.5 -d mongoc-stat $PID may be used to monitor an
       application.

       Performance counters are only available on Linux platforms and macOS arm64 platforms  that
       support  shared  memory  segments.   On  supported platforms, they are enabled by default.
       Applications  can  be  built  without  the  counters  by  specifying  the   cmake   option
       -DENABLE_SHM_COUNTERS=OFF.   Additionally,  if  performance counters are already compiled,
       they can be disabled at runtime by specifying the environment variable MONGOC_DISABLE_SHM.

       Performance counters keep track of the following:

       • Active and Disposed Cursors

       • Active and Disposed Clients, Client Pools, and Socket Streams.

       • Number of operations sent and received, by type.

       • Bytes transferred and received.

       • Authentication successes and failures.

       • Number of wire protocol errors.

       NOTE:
          An operation is considered "sent" when one or more bytes of the  corresponding  message
          is  written  to  the  stream,  regardless of whether the entire message is successfully
          written or if the operation ultimately succeeds or fails.  This does not include  bytes
          that  may  be  written  during  the  stream  connection  process, such as TLS handshake
          messages.

       To access counters for a given process, simply provide the process id to  the  mongoc-stat
       program installed with the MongoDB C Driver.

          $ mongoc-stat 22203
             Operations : Egress Total        : The number of sent operations.                    : 13247
             Operations : Ingress Total       : The number of received operations.                : 13246
             Operations : Egress Queries      : The number of sent Query operations.              : 13247
             Operations : Ingress Queries     : The number of received Query operations.          : 0
             Operations : Egress GetMore      : The number of sent GetMore operations.            : 0
             Operations : Ingress GetMore     : The number of received GetMore operations.        : 0
             Operations : Egress Insert       : The number of sent Insert operations.             : 0
             Operations : Ingress Insert      : The number of received Insert operations.         : 0
             Operations : Egress Delete       : The number of sent Delete operations.             : 0
             Operations : Ingress Delete      : The number of received Delete operations.         : 0
             Operations : Egress Update       : The number of sent Update operations.             : 0
             Operations : Ingress Update      : The number of received Update operations.         : 0
             Operations : Egress KillCursors  : The number of sent KillCursors operations.        : 0
             Operations : Ingress KillCursors : The number of received KillCursors operations.    : 0
             Operations : Egress Msg          : The number of sent Msg operations.                : 0
             Operations : Ingress Msg         : The number of received Msg operations.            : 0
             Operations : Egress Reply        : The number of sent Reply operations.              : 0
             Operations : Ingress Reply       : The number of received Reply operations.          : 13246
                Cursors : Active              : The number of active cursors.                     : 1
                Cursors : Disposed            : The number of disposed cursors.                   : 13246
                Clients : Active              : The number of active clients.                     : 1
                Clients : Disposed            : The number of disposed clients.                   : 0
                Streams : Active              : The number of active streams.                     : 1
                Streams : Disposed            : The number of disposed streams.                   : 0
                Streams : Egress Bytes        : The number of bytes sent.                         : 794931
                Streams : Ingress Bytes       : The number of bytes received.                     : 589694
                Streams : N Socket Timeouts   : The number of socket timeouts.                    : 0
           Client Pools : Active              : The number of active client pools.                : 1
           Client Pools : Disposed            : The number of disposed client pools.              : 0
               Protocol : Ingress Errors      : The number of protocol errors on ingress.         : 0
                   Auth : Failures            : The number of failed authentication requests.     : 0
                   Auth : Success             : The number of successful authentication requests. : 0

   Submitting a Bug Report
       Think you've found a bug? Want to see a new feature in the MongoDB C driver? Please open a
       case in our issue management tool, JIRA:

       • Create an account and login.

       • Navigate to the CDRIVER project.

       • Click Create Issue - Please provide as much information as possible about the issue type
         and how to reproduce it.

       Bug  reports  in  JIRA  for  all driver projects (i.e. CDRIVER, CSHARP, JAVA) and the Core
       Server (i.e. SERVER) project are public.

   Guides
   Configuring TLS
   Configuration with URI options
       Enable TLS by including tls=true in the URI.

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
          mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);

          mongoc_client_t *client = mongoc_client_new_from_uri (uri);

       The following URI options may be used to further configure TLS:

┌────────────────────────────────────────────────┬──────────────────────────────────────┬────────────────────────────────────────┐
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
└────────────────────────────────────────────────┴──────────────────────────────────────┴────────────────────────────────────────┘
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
├────────────────────────────────────────────────┼──────────────────────────────────────┼────────────────────────────────────────┤
└────────────────────────────────────────────────┴──────────────────────────────────────┴────────────────────────────────────────┘

   Configuration with mongoc_ssl_opt_t
       Alternatively,  the  mongoc_ssl_opt_t  struct  may  be  used   to   configure   TLS   with
       mongoc_client_set_ssl_opts()    or    mongoc_client_pool_set_ssl_opts().   Most   of   the
       configurable options can be set using the Connection String URI.

                       ┌───────────────────────┬─────────────────────────────────┐
                       │mongoc_ssl_opt_t keyURI key                         │
                       ├───────────────────────┼─────────────────────────────────┤
                       │pem_file               │ tlsClientCertificateKeyFile     │
                       ├───────────────────────┼─────────────────────────────────┤
                       │pem_pwd                │ tlsClientCertificateKeyPassword │
                       ├───────────────────────┼─────────────────────────────────┤
                       │ca_file                │ tlsCAFile                       │
                       ├───────────────────────┼─────────────────────────────────┤
                       │weak_cert_validation   │ tlsAllowInvalidCertificates     │
                       ├───────────────────────┼─────────────────────────────────┤
                       │allow_invalid_hostname │ tlsAllowInvalidHostnames        │
                       └───────────────────────┴─────────────────────────────────┘

       The only exclusions are crl_file and ca_dir. Those may only be set with mongoc_ssl_opt_t.

   Client Authentication
       When MongoDB is started with TLS enabled, it will by default require the client to provide
       a  client  certificate  issued  by a certificate authority specified by --tlsCAFile, or an
       authority trusted by the native certificate store in use on the server.

       To provide the client certificate, set the tlsCertificateKeyFile  in  the  URI  to  a  PEM
       armored certificate file.

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/");
          mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true);
          mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "/path/to/client-certificate.pem");

          mongoc_client_t *client = mongoc_client_new_from_uri (uri);

   Server Certificate Verification
       The  MongoDB  C  Driver  will automatically verify the validity of the server certificate,
       such as issued by configured Certificate Authority, hostname validation, and expiration.

       To overwrite this behavior, it is possible to disable hostname validation,  OCSP  endpoint
       revocation checking, revocation checking entirely, and allow invalid certificates.

       This      behavior      is      controlled     using     the     tlsAllowInvalidHostnames,
       tlsDisableOCSPEndpointCheck,           tlsDisableCertificateRevocationCheck,           and
       tlsAllowInvalidCertificates options respectively. By default, all are set to false.

       It  is  not  recommended  to  change these defaults as it exposes the client to Man In The
       Middle  attacks  (when  tlsAllowInvalidHostnames  is  set),  invalid  certificates   (when
       tlsAllowInvalidCertificates   is   set),   or   potentially   revoked  certificates  (when
       tlsDisableOCSPEndpointCheck or tlsDisableCertificateRevocationCheck are set).

   Supported Libraries
       By default, libmongoc will attempt to find a supported TLS library and enable TLS support.
       This  is  controlled  by the cmake flag ENABLE_SSL, which is set to AUTO by default. Valid
       values are:

       • AUTO the default behavior. Link to the system's native TLS library, or attempt  to  find
         OpenSSL.

       • DARWIN link to Secure Transport, the native TLS library on macOS.

       • WINDOWS link to Secure Channel, the native TLS library on Windows.

       • OPENSSL  link  to  OpenSSL  (libssl).  An  optional  install  path may be specified with
         OPENSSL_ROOT.

       • LIBRESSL link to LibreSSL's libtls. (LibreSSL's compatible libssl may be  linked  to  by
         setting OPENSSL).

       • OFF disable TLS support.

   OpenSSL
       The  MongoDB  C  Driver  uses  OpenSSL, if available, on Linux and Unix platforms (besides
       macOS). Industry best practices and some regulations require the use of TLS 1.1 or  newer,
       which requires at least OpenSSL 1.0.1. Check your OpenSSL version like so:

          $ openssl version

       Ensure  your  system's  OpenSSL  is a recent version (at least 1.0.1), or install a recent
       version in a non-system path and build against it with:

          cmake -DOPENSSL_ROOT_DIR=/absolute/path/to/openssl

       When compiled against OpenSSL,  the  driver  will  attempt  to  load  the  system  default
       certificate  store,  as  configured by the distribution. That can be overridden by setting
       the tlsCAFile URI option or with the fields ca_file and ca_dir in the mongoc_ssl_opt_t.

       The Online Certificate Status Protocol (OCSP) (see RFC 6960) is fully supported when using
       OpenSSL 1.0.1+ with the following notes:

       • When  a  crl_file  is  set  with mongoc_ssl_opt_t, and the crl_file revokes the server's
         certificate, the certificate is considered revoked (even if the certificate has a  valid
         stapled OCSP response)

   LibreSSL / libtls
       The  MongoDB  C  Driver  supports LibreSSL through the use of OpenSSL compatibility checks
       when configured to compile against openssl. It also supports the new libtls  library  when
       configured to build against libressl.

       When   compiled   against   the  Windows  native  libraries,  the  crl_file  option  of  a
       mongoc_ssl_opt_t is not supported, and will issue an error if used.

       Setting  tlsDisableOCSPEndpointCheck  and  tlsDisableCertificateRevocationCheck   has   no
       effect.

       The  Online  Certificate Status Protocol (OCSP) (see RFC 6960) is partially supported with
       the following notes:

       • The Must-Staple extension (see RFC 7633)  is  ignored.  Connection  may  continue  if  a
         Must-Staple  certificate  is  presented  with  no  stapled  response  (unless the client
         receives a revoked response from an OCSP responder).

       • Connection will continue if a Must-Staple certificate is  presented  without  a  stapled
         response and the OCSP responder is down.

   Native TLS Support on Windows (Secure Channel)
       The  MongoDB  C  Driver  supports  the  Windows  native  TLS  library  (Secure Channel, or
       SChannel), and its native crypto library (Cryptography API: Next Generation, or CNG).

       When  compiled  against  the  Windows  native  libraries,   the   ca_dir   option   of   a
       mongoc_ssl_opt_t is not supported, and will issue an error if used.

       Encrypted  PEM files (e.g., setting tlsCertificateKeyPassword) are also not supported, and
       will result in error when attempting to load them.

       When tlsCAFile is set, the driver will  only  allow  server  certificates  issued  by  the
       authority (or authorities) provided. When no tlsCAFile is set, the driver will look up the
       Certificate Authority using the System Local Machine Root certificate store to confirm the
       provided certificate.

       When  crl_file is set with mongoc_ssl_opt_t, the driver will import the revocation list to
       the System Local Machine Root certificate store.

       Setting tlsDisableOCSPEndpointCheck has no effect.

       The Online Certificate Status Protocol (OCSP) (see RFC 6960) is partially  supported  with
       the following notes:

       • The  Must-Staple  extension  (see  RFC  7633)  is  ignored. Connection may continue if a
         Must-Staple certificate is  presented  with  no  stapled  response  (unless  the  client
         receives a revoked response from an OCSP responder).

       • When  a  crl_file  is  set  with mongoc_ssl_opt_t, and the crl_file revokes the server's
         certificate, the  OCSP  response  takes  precedence.  E.g.  if  the  server  presents  a
         certificate with a valid stapled OCSP response, the certificate is considered valid even
         if the crl_file marks it as revoked.

       • Connection will continue if a Must-Staple certificate is  presented  without  a  stapled
         response and the OCSP responder is down.

   Native TLS Support on macOS / Darwin (Secure Transport)
       The  MongoDB  C  Driver  supports  the  Darwin (OS X, macOS, iOS, etc.) native TLS library
       (Secure Transport), and its native crypto library (Common Crypto, or CC).

       When  compiled  against  Secure  Transport,  the  ca_dir  and  crl_file   options   of   a
       mongoc_ssl_opt_t are not supported. An error is issued if either are used.

       When  tlsCAFile  is  set,  the  driver  will  only allow server certificates issued by the
       authority (or authorities) provided. When no tlsCAFile is set, the  driver  will  use  the
       Certificate Authorities in the currently unlocked keychains.

       Setting   tlsDisableOCSPEndpointCheck   and  tlsDisableCertificateRevocationCheck  has  no
       effect.

       The Online Certificate Status Protocol (OCSP) (see RFC 6960) is partially  supported  with
       the following notes.

       • The  Must-Staple  extension  (see  RFC  7633)  is  ignored. Connection may continue if a
         Must-Staple certificate is  presented  with  no  stapled  response  (unless  the  client
         receives a revoked response from an OCSP responder).

       • Connection  will  continue  if  a Must-Staple certificate is presented without a stapled
         response and the OCSP responder is down.

   Common Tasks
       Drivers for some other languages provide helper functions to perform certain common tasks.
       In the C Driver we must explicitly build commands to send to the server.

   Setup
       First we'll write some code to insert sample data:

       doc-common-insert.c

          /* Don't try to compile this file on its own. It's meant to be #included
             by example code */

          /* Insert some sample data */
          bool
          insert_data (mongoc_collection_t *collection)
          {
             mongoc_bulk_operation_t *bulk;
             enum N { ndocs = 4 };
             bson_t *docs[ndocs];
             bson_error_t error;
             int i = 0;
             bool ret;

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);

             docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
             docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
             docs[2] = BCON_NEW (
                "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
             docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");

             for (i = 0; i < ndocs; i++) {
                mongoc_bulk_operation_insert (bulk, docs[i]);
                bson_destroy (docs[i]);
                docs[i] = NULL;
             }

             ret = mongoc_bulk_operation_execute (bulk, NULL, &error);

             if (!ret) {
                fprintf (stderr, "Error inserting data: %s\n", error.message);
             }

             mongoc_bulk_operation_destroy (bulk);
             return ret;
          }

          /* A helper which we'll use a lot later on */
          void
          print_res (const bson_t *reply)
          {
             char *str;
             BSON_ASSERT (reply);
             str = bson_as_canonical_extended_json (reply, NULL);
             printf ("%s\n", str);
             bson_free (str);
          }

   "explain" Command
       This is how to use the explain command in MongoDB 3.2+:

       explain.c

          bool
          explain (mongoc_collection_t *collection)
          {
             bson_t *command;
             bson_t reply;
             bson_error_t error;
             bool res;

             command = BCON_NEW ("explain",
                                 "{",
                                 "find",
                                 BCON_UTF8 (COLLECTION_NAME),
                                 "filter",
                                 "{",
                                 "x",
                                 BCON_INT32 (1),
                                 "}",
                                 "}");
             res = mongoc_collection_command_simple (
                collection, command, NULL, &reply, &error);
             if (!res) {
                fprintf (stderr, "Error with explain: %s\n", error.message);
                goto cleanup;
             }

             /* Do something with the reply */
             print_res (&reply);

          cleanup:
             bson_destroy (&reply);
             bson_destroy (command);
             return res;
          }

   Running the Examples
       common-operations.c

          /*
           * Copyright 2016 MongoDB, Inc.
           *
           * Licensed under the Apache License, Version 2.0 (the "License");
           * you may not use this file except in compliance with the License.
           * You may obtain a copy of the License at
           *
           *   http://www.apache.org/licenses/LICENSE-2.0
           *
           * Unless required by applicable law or agreed to in writing, software
           * distributed under the License is distributed on an "AS IS" BASIS,
           * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           * See the License for the specific language governing permissions and
           * limitations under the License.
           */

          #include <mongoc/mongoc.h>
          #include <stdio.h>

          const char *COLLECTION_NAME = "things";

          #include "../doc-common-insert.c"
          #include "explain.c"

          int
          main (int argc, char *argv[])
          {
             mongoc_database_t *database = NULL;
             mongoc_client_t *client = NULL;
             mongoc_collection_t *collection = NULL;
             mongoc_uri_t *uri = NULL;
             bson_error_t error;
             char *host_and_port;
             int res = 0;

             if (argc < 2 || argc > 3) {
                fprintf (stderr,
                         "usage: %s MONGOD-1-CONNECTION-STRING "
                         "[MONGOD-2-HOST-NAME:MONGOD-2-PORT]\n",
                         argv[0]);
                fprintf (stderr,
                         "MONGOD-1-CONNECTION-STRING can be "
                         "of the following forms:\n");
                fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
                fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
                fprintf (stderr,
                         "mongodb://user:pass@localhost:27017\t"
                         "local machine on port 27017, and authenticate with username "
                         "user and password pass\n");
                return EXIT_FAILURE;
             }

             mongoc_init ();

             if (strncmp (argv[1], "mongodb://", 10) == 0) {
                host_and_port = bson_strdup (argv[1]);
             } else {
                host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
             }

             uri = mongoc_uri_new_with_error (host_and_port, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         host_and_port,
                         error.message);
                res = EXIT_FAILURE;
                goto cleanup;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                res = EXIT_FAILURE;
                goto cleanup;
             }

             mongoc_client_set_error_api (client, 2);
             database = mongoc_client_get_database (client, "test");
             collection = mongoc_database_get_collection (database, COLLECTION_NAME);

             printf ("Inserting data\n");
             if (!insert_data (collection)) {
                res = EXIT_FAILURE;
                goto cleanup;
             }

             printf ("explain\n");
             if (!explain (collection)) {
                res = EXIT_FAILURE;
                goto cleanup;
             }

          cleanup:
             if (collection) {
                mongoc_collection_destroy (collection);
             }

             if (database) {
                mongoc_database_destroy (database);
             }

             if (client) {
                mongoc_client_destroy (client);
             }

             if (uri) {
                mongoc_uri_destroy (uri);
             }

             bson_free (host_and_port);
             mongoc_cleanup ();
             return res;
          }

       First launch two separate instances of mongod (must be done from separate shells):

          $ mongod

          $ mkdir /tmp/db2
          $ mongod --dbpath /tmp/db2 --port 27018 # second instance

       Now compile and run the example program:

          $ cd examples/common_operations/$ gcc -Wall -o example common-operations.c $(pkg-config --cflags --libs libmongoc-1.0)$ ./example localhost:27017 localhost:27018
          Inserting data
          explain
          {
             "executionStats" : {
                "allPlansExecution" : [],
                "executionStages" : {
                   "advanced" : 19,
                   "direction" : "forward" ,
                   "docsExamined" : 76,
                   "executionTimeMillisEstimate" : 0,
                   "filter" : {
                      "x" : {
                         "$eq" : 1
                      }
                   },
                   "invalidates" : 0,
                   "isEOF" : 1,
                   "nReturned" : 19,
                   "needTime" : 58,
                   "needYield" : 0,
                   "restoreState" : 0,
                   "saveState" : 0,
                   "stage" : "COLLSCAN" ,
                   "works" : 78
                },
                "executionSuccess" : true,
                "executionTimeMillis" : 0,
                "nReturned" : 19,
                "totalDocsExamined" : 76,
                "totalKeysExamined" : 0
             },
             "ok" : 1,
             "queryPlanner" : {
                "indexFilterSet" : false,
                "namespace" : "test.things",
                "parsedQuery" : {
                   "x" : {
                      "$eq" : 1
                   }
                },
                "plannerVersion" : 1,
                "rejectedPlans" : [],
                "winningPlan" : {
                   "direction" : "forward" ,
                   "filter" : {
                      "x" : {
                         "$eq" : 1
                      }
                   },
                   "stage" : "COLLSCAN"
                }
             },
             "serverInfo" : {
                "gitVersion" : "05552b562c7a0b3143a729aaa0838e558dc49b25" ,
                "host" : "MacBook-Pro-57.local",
                "port" : 27017,
                "version" : "3.2.6"
             }
          }

   Advanced Connections
       The   following   guide   contains  information  specific  to  certain  types  of  MongoDB
       configurations.

       For an example of connecting to a simple standalone server, see the Tutorial. To establish
       a  connection  with authentication options enabled, see the Authentication page. To see an
       example of a connection with data compression, see the Data Compression page.

   Connecting to a Replica Set
       Connecting to a replica set is much like connecting to a standalone MongoDB server. Simply
       specify the replica set name using the ?replicaSet=myreplset URI option.

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;

             mongoc_init ();

             /* Create our MongoDB Client */
             client = mongoc_client_new (
                "mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset");

             /* Do some work */
             /* TODO */

             /* Clean up */
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return 0;
          }

       TIP:
          Multiple  hostnames can be specified in the MongoDB connection string URI, with a comma
          separating hosts in the seed list.

          It is recommended to use a seed list of members of the replica set to allow the  driver
          to connect to any node.

   Connecting to a Sharded Cluster
       To  connect  to  a sharded cluster, specify the mongos nodes the client should connect to.
       The C Driver will automatically detect that it has connected to a mongos sharding server.

       If more than one hostname is specified, a seed list will be created  to  attempt  failover
       between the mongos instances.

       WARNING:
          Specifying  the  replicaSet  parameter  when  connecting to a mongos sharding server is
          invalid.

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;

             mongoc_init ();

             /* Create our MongoDB Client */
             client = mongoc_client_new ("mongodb://myshard01:27017/");

             /* Do something with client ... */

             /* Free the client */
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return 0;
          }

   Connecting to an IPv6 Address
       The MongoDB C Driver will automatically resolve IPv6 addresses from host  names.  However,
       to specify an IPv6 address directly, wrap the address in [].

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://[::1]:27017");

   Connecting with IPv4 and IPv6
       If  connecting to a hostname that has both IPv4 and IPv6 DNS records, the behavior follows
       RFC-6555. A connection to the IPv6 address is attempted  first.  If  IPv6  fails,  then  a
       connection  is  attempted  to the IPv4 address. If the connection attempt to IPv6 does not
       complete within 250ms, then IPv4 is tried in parallel. Whichever succeeds connection first
       cancels the other. The successful DNS result is cached for 10 minutes.

       As a consequence, attempts to connect to a mongod only listening on IPv4 may be delayed if
       there are both A (IPv4) and AAAA (IPv6) DNS records associated with the host.

       To avoid a delay, configure hostnames to match the MongoDB configuration.  That  is,  only
       create an A record if the mongod is only listening on IPv4.

   Connecting to a UNIX Domain Socket
       On  UNIX-like  systems, the C Driver can connect directly to a MongoDB server using a UNIX
       domain socket. Pass the URL-encoded path to the socket, which must be suffixed with .sock.
       For example, to connect to a domain socket at /tmp/mongodb-27017.sock:

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://%2Ftmp%2Fmongodb-27017.sock");

       Include username and password like so:

          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://user:pass@%2Ftmp%2Fmongodb-27017.sock");

   Connecting to a server over TLS
       These are instructions for configuring TLS/SSL connections.

       To run a server locally (on port 27017, for example):

          $ mongod --port 27017 --tlsMode requireTLS --tlsCertificateKeyFile server.pem --tlsCAFile ca.pem

       Add /?tls=true to the end of a client URI.

          mongoc_client_t *client = NULL;
          client = mongoc_client_new ("mongodb://localhost:27017/?tls=true");

       MongoDB      requires      client      certificates     by     default,     unless     the
       --tlsAllowConnectionsWithoutCertificates is provided. The C Driver can  be  configured  to
       present  a  client  certificate  using  the URI option tlsCertificateKeyFile, which may be
       referenced through the constant MONGOC_URI_TLSCERTIFICATEKEYFILE.

          mongoc_client_t *client = NULL;
          mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/?tls=true");
          mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "client.pem");

          client = mongoc_client_new_from_uri (uri);

       The client certificate provided by tlsCertificateKeyFile must be  issued  by  one  of  the
       server  trusted  Certificate  Authorities  listed in --tlsCAFile, or issued by a CA in the
       native certificate store on the server when omitted.

       See Configuring TLS for more information on the various TLS related options.

   Compressing data to and from MongoDB
       This content has been relocated to the Data Compression page.

   Additional Connection Options
       The full list of connection options can be found in the mongoc_uri_t docs.

       Certain socket/connection related options are not configurable:

                  ┌──────────────┬──────────────────────────┬────────────────────────┐
                  │Option        │ Description              │ Value                  │
                  ├──────────────┼──────────────────────────┼────────────────────────┤
                  │SO_KEEPALIVE  │ TCP Keep Alive           │ Enabled                │
                  ├──────────────┼──────────────────────────┼────────────────────────┤
                  │TCP_KEEPIDLE  │ How  long  a  connection │ 120 seconds            │
                  │              │ needs   to  remain  idle │                        │
                  │              │ before    TCP     starts │                        │
                  │              │ sending keepalive probes │                        │
                  ├──────────────┼──────────────────────────┼────────────────────────┤
                  │TCP_KEEPINTVL │ The   time   in  seconds │ 10 seconds             │
                  │              │ between TCP probes       │                        │
                  ├──────────────┼──────────────────────────┼────────────────────────┤
                  │TCP_KEEPCNT   │ How many probes to send, │ 9 probes               │
                  │              │ without acknowledgement, │                        │
                  │              │ before   dropping    the │                        │
                  │              │ connection               │                        │
                  └──────────────┴──────────────────────────┴────────────────────────┘

                  │TCP_NODELAY   │ Send  packets as soon as │ Enabled (no buffering) │
                  │              │ possible or buffer small │                        │
                  │              │ packets           (Nagle │                        │
                  │              │ algorithm)               │                        │
                  └──────────────┴──────────────────────────┴────────────────────────┘

   Connection Pooling
       The MongoDB C driver has two connection modes: single-threaded and pooled. Single-threaded
       mode  is  optimized  for  embedding  the  driver within languages like PHP. Multi-threaded
       programs should use pooled mode: this mode minimizes the total connection  count,  and  in
       pooled  mode  background  threads monitor the MongoDB server topology, so the program need
       not block to scan it.

   Single Mode
       In single mode, your program creates a mongoc_client_t directly:

          mongoc_client_t *client = mongoc_client_new (
             "mongodb://hostA,hostB/?replicaSet=my_rs");

       The client connects on demand when your program first uses it  for  a  MongoDB  operation.
       Using a non-blocking socket per server, it begins a check on each server concurrently, and
       uses the asynchronous poll or select function to receive events from  the  sockets,  until
       all  have  responded  or  timed out. Put another way, in single-threaded mode the C Driver
       fans out to begin all checks concurrently, then fans in once all checks have completed  or
       timed  out.  Once  the  scan  completes,  the client executes your program's operation and
       returns.

       In single mode, the client re-scans the server topology roughly once per minute.  If  more
       than  a  minute has elapsed since the previous scan, the next operation on the client will
       block  while  the  client  completes  its  scan.  This  interval  is   configurable   with
       heartbeatFrequencyMS in the connection string. (See mongoc_uri_t.)

       A  single  client  opens one connection per server in your topology: these connections are
       used both for scanning the topology and performing normal operations.

   Pooled Mode
       To activate pooled mode, create a mongoc_client_pool_t:

          mongoc_uri_t *uri = mongoc_uri_new (
             "mongodb://hostA,hostB/?replicaSet=my_rs");

          mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);

       When your program first  calls  mongoc_client_pool_pop(),  the  pool  launches  monitoring
       threads  in the background. Monitoring threads independently connect to all servers in the
       connection string. As monitoring threads receive hello responses from  the  servers,  they
       update  the  shared  view  of  the  server  topology.  Additional  monitoring  threads and
       connections are created as new servers are discovered. Monitoring threads  are  terminated
       when servers are removed from the shared view of the server topology.

       Each thread that executes MongoDB operations must check out a client from the pool:

          mongoc_client_t *client = mongoc_client_pool_pop (pool);

          /* use the client for operations ... */

          mongoc_client_pool_push (pool, client);

       The mongoc_client_t object is not thread-safe, only the mongoc_client_pool_t is.

       When  the  driver  is  in  pooled mode, your program's operations are unblocked as soon as
       monitoring discovers a usable server. For example, if a thread in your program is  waiting
       to  execute  an  "insert"  on  the  primary,  it  is  unblocked  as soon as the primary is
       discovered, rather than waiting for all secondaries to be checked as well.

       The pool opens one connection per server for monitoring, and each  client  opens  its  own
       connection  to  each  server  it  uses  for  application operations. Background monitoring
       threads  re-scan  servers  independently  roughly  every  10  seconds.  This  interval  is
       configurable with heartbeatFrequencyMS in the connection string. (See mongoc_uri_t.)

       The  connection  string  can  also  specify  waitQueueTimeoutMS  to  limit  the  time that
       mongoc_client_pool_pop() will wait for a client from the pool.   (See  mongoc_uri_t.)   If
       waitQueueTimeoutMS  is  specified,  then  it  is  necessary  to  confirm that a client was
       actually returned:

          mongoc_uri_t *uri = mongoc_uri_new (
             "mongodb://hostA,hostB/?replicaSet=my_rs&waitQueueTimeoutMS=1000");

          mongoc_client_pool_t *pool = mongoc_client_pool_new (uri);

          mongoc_client_t *client = mongoc_client_pool_pop (pool);

          if (client) {
             /* use the client for operations ... */

             mongoc_client_pool_push (pool, client);
          } else {
             /* take appropriate action for a timeout */
          }

       See  Connection  Pool  Options  to   configure   pool   size   and   behavior,   and   see
       mongoc_client_pool_t  for  an  extended  example of a multi-threaded program that uses the
       driver in pooled mode.

   Data Compression
       The following guide explains how data compression support works between the MongoDB server
       and client. It also shows an example of how to connect to a server with data compression.

   Compressing data to and from MongoDB
       MongoDB 3.4 added Snappy compression support, while zlib compression was added in 3.6, and
       zstd compression in 4.2.  To enable compression support the client must be configured with
       which compressors to use:

          mongoc_client_t *client = NULL;
          client = mongoc_client_new ("mongodb://localhost:27017/?compressors=snappy,zlib,zstd");

       The  compressors  option  specifies  the priority order of compressors the client wants to
       use. Messages are compressed if the client and server share any compressors in common.

       Note that the compressor used by the server might not be the same compressor as the client
       used.   For  example, if the client uses the connection string compressors=zlib,snappy the
       client will use zlib compression to send data (if possible), but the  server  might  still
       reply using snappy, depending on how the server was configured.

       The driver must be built with zlib and/or snappy and/or zstd support to enable compression
       support, any unknown (or not compiled in) compressor value will be ignored.

   Cursors
   Handling Cursor Failures
       Cursors exist on a MongoDB server. However, the mongoc_cursor_t structure gives the  local
       process  a  handle  to  the cursor. It is possible for errors to occur on the server while
       iterating a cursor on the client. Even a network partition  may  occur.  This  means  that
       applications should be robust in handling cursor failures.

       While  iterating  cursors,  you  should  check  to  see  if an error has occurred. See the
       following example for how to robustly check for errors.

          static void
          print_all_documents (mongoc_collection_t *collection)
          {
             mongoc_cursor_t *cursor;
             const bson_t *doc;
             bson_error_t error;
             bson_t query = BSON_INITIALIZER;
             char *str;

             cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_canonical_extended_json (doc, NULL);
                printf ("%s\n", str);
                bson_free (str);
             }

             if (mongoc_cursor_error (cursor, &error)) {
                fprintf (stderr, "Failed to iterate all documents: %s\n", error.message);
             }

             mongoc_cursor_destroy (cursor);
          }

   Destroying Server-Side Cursors
       The  MongoDB  C  driver   will   automatically   destroy   a   server-side   cursor   when
       mongoc_cursor_destroy()  is  called. Failure to call this function when done with a cursor
       will leak memory client side as well as consume extra memory server side.  If  the  cursor
       was configured to never timeout, it will become a memory leak on the server.

   Tailable Cursors
       Tailable  cursors are cursors that remain open even after they've returned a final result.
       This way, if more documents are added to a collection (i.e., to the cursor's result  set),
       then you can continue to call mongoc_cursor_next() to retrieve those additional results.

       Here's a complete test case that demonstrates the use of tailable cursors.

       NOTE:
          Tailable cursors are for capped collections only.

       An example to tail the oplog from a replica set.

       mongoc-tail.c

          #include <bson/bson.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>

          #ifdef _WIN32
          #define sleep(_n) Sleep ((_n) *1000)
          #endif

          static void
          print_bson (const bson_t *b)
          {
             char *str;

             str = bson_as_canonical_extended_json (b, NULL);
             fprintf (stdout, "%s\n", str);
             bson_free (str);
          }

          static mongoc_cursor_t *
          query_collection (mongoc_collection_t *collection, uint32_t last_time)
          {
             mongoc_cursor_t *cursor;
             bson_t query;
             bson_t gt;
             bson_t opts;

             BSON_ASSERT (collection);

             bson_init (&query);
             BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", &gt);
             BSON_APPEND_TIMESTAMP (&gt, "$gt", last_time, 0);
             bson_append_document_end (&query, &gt);

             bson_init (&opts);
             BSON_APPEND_BOOL (&opts, "tailable", true);
             BSON_APPEND_BOOL (&opts, "awaitData", true);

             cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL);

             bson_destroy (&query);
             bson_destroy (&opts);

             return cursor;
          }

          static void
          tail_collection (mongoc_collection_t *collection)
          {
             mongoc_cursor_t *cursor;
             uint32_t last_time;
             const bson_t *doc;
             bson_error_t error;
             bson_iter_t iter;

             BSON_ASSERT (collection);

             last_time = (uint32_t) time (NULL);

             while (true) {
                cursor = query_collection (collection, last_time);
                while (!mongoc_cursor_error (cursor, &error) &&
                       mongoc_cursor_more (cursor)) {
                   if (mongoc_cursor_next (cursor, &doc)) {
                      if (bson_iter_init_find (&iter, doc, "ts") &&
                          BSON_ITER_HOLDS_TIMESTAMP (&iter)) {
                         bson_iter_timestamp (&iter, &last_time, NULL);
                      }
                      print_bson (doc);
                   }
                }
                if (mongoc_cursor_error (cursor, &error)) {
                   if (error.domain == MONGOC_ERROR_SERVER) {
                      fprintf (stderr, "%s\n", error.message);
                      exit (1);
                   }
                }

                mongoc_cursor_destroy (cursor);
                sleep (1);
             }
          }

          int
          main (int argc, char *argv[])
          {
             mongoc_collection_t *collection;
             mongoc_client_t *client;
             mongoc_uri_t *uri;
             bson_error_t error;

             if (argc != 2) {
                fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]);
                return EXIT_FAILURE;
             }

             mongoc_init ();

             uri = mongoc_uri_new_with_error (argv[1], &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         argv[1],
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);

             collection = mongoc_client_get_collection (client, "local", "oplog.rs");

             tail_collection (collection);

             mongoc_collection_destroy (collection);
             mongoc_uri_destroy (uri);
             mongoc_client_destroy (client);

             return EXIT_SUCCESS;
          }

       Let's compile and run this example against a replica set to see updates as they are made.

          $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet
          {
              "h" : -8458503739429355503,
              "ns" : "test.test",
              "o" : {
                  "_id" : {
                      "$oid" : "5372ab0a25164be923d10d50"
                  }
              },
              "op" : "i",
              "ts" : {
                  "$timestamp" : {
                      "i" : 1,
                      "t" : 1400023818
                  }
              },
              "v" : 2
          }

       The  line of output is a sample from performing db.test.insert({}) from the mongo shell on
       the replica set.

       SEE ALSO:
          mongoc_cursor_set_max_await_time_ms().

   Bulk Write Operations
       This tutorial explains how to take advantage of MongoDB  C  driver  bulk  write  operation
       features. Executing write operations in batches reduces the number of network round trips,
       increasing write throughput.

   Bulk Insert
       First we need to fetch a bulk operation handle from the mongoc_collection_t.

          mongoc_bulk_operation_t *bulk =
             mongoc_collection_create_bulk_operation_with_opts (collection, NULL);

       We can now start inserting documents to the bulk operation. These will be  buffered  until
       we execute the operation.

       The bulk operation will coalesce insertions as a single batch for each consecutive call to
       mongoc_bulk_operation_insert(). This creates a pipelined effect when possible.

       To    execute    the    bulk    operation    and    receive    the    result    we    call
       mongoc_bulk_operation_execute().

       bulk1.c

          #include <assert.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          bulk1 (mongoc_collection_t *collection)
          {
             mongoc_bulk_operation_t *bulk;
             bson_error_t error;
             bson_t *doc;
             bson_t reply;
             char *str;
             bool ret;
             int i;

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);

             for (i = 0; i < 10000; i++) {
                doc = BCON_NEW ("i", BCON_INT32 (i));
                mongoc_bulk_operation_insert (bulk, doc);
                bson_destroy (doc);
             }

             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                fprintf (stderr, "Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             mongoc_bulk_operation_destroy (bulk);
          }

          int
          main (void)
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             const char *uri_string = "mongodb://localhost/?appname=bulk1-example";
             mongoc_uri_t *uri;
             bson_error_t error;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             collection = mongoc_client_get_collection (client, "test", "test");

             bulk1 (collection);

             mongoc_uri_destroy (uri);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       Example reply document:

          {"nInserted"   : 10000,
           "nMatched"    : 0,
           "nModified"   : 0,
           "nRemoved"    : 0,
           "nUpserted"   : 0,
           "writeErrors" : []
           "writeConcernErrors" : [] }

   Mixed Bulk Write Operations
       MongoDB  C  driver also supports executing mixed bulk write operations. A batch of insert,
       update, and remove operations can be executed together using  the  bulk  write  operations
       API.

   Ordered Bulk Write Operations
       Ordered bulk write operations are batched and sent to the server in the order provided for
       serial execution. The reply document describes the type and count of operations performed.

       bulk2.c

          #include <assert.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          bulk2 (mongoc_collection_t *collection)
          {
             mongoc_bulk_operation_t *bulk;
             bson_error_t error;
             bson_t *query;
             bson_t *doc;
             bson_t *opts;
             bson_t reply;
             char *str;
             bool ret;
             int i;

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);

             /* Remove everything */
             query = bson_new ();
             mongoc_bulk_operation_remove (bulk, query);
             bson_destroy (query);

             /* Add a few documents */
             for (i = 1; i < 4; i++) {
                doc = BCON_NEW ("_id", BCON_INT32 (i));
                mongoc_bulk_operation_insert (bulk, doc);
                bson_destroy (doc);
             }

             /* {_id: 1} => {$set: {foo: "bar"}} */
             query = BCON_NEW ("_id", BCON_INT32 (1));
             doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}");
             mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, NULL, &error);
             bson_destroy (query);
             bson_destroy (doc);

             /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */
             opts = BCON_NEW ("upsert", BCON_BOOL (true));
             query = BCON_NEW ("_id", BCON_INT32 (4));
             doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}");
             mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, opts, &error);
             bson_destroy (query);
             bson_destroy (doc);
             bson_destroy (opts);

             /* replace {j:1} with {j:2} */
             query = BCON_NEW ("j", BCON_INT32 (1));
             doc = BCON_NEW ("j", BCON_INT32 (2));
             mongoc_bulk_operation_replace_one_with_opts (bulk, query, doc, NULL, &error);
             bson_destroy (query);
             bson_destroy (doc);

             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                printf ("Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             mongoc_bulk_operation_destroy (bulk);
          }

          int
          main (void)
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             const char *uri_string = "mongodb://localhost/?appname=bulk2-example";
             mongoc_uri_t *uri;
             bson_error_t error;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             collection = mongoc_client_get_collection (client, "test", "test");

             bulk2 (collection);

             mongoc_uri_destroy (uri);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       Example reply document:

          { "nInserted"   : 3,
            "nMatched"    : 2,
            "nModified"   : 2,
            "nRemoved"    : 10000,
            "nUpserted"   : 1,
            "upserted"    : [{"index" : 5, "_id" : 4}],
            "writeErrors" : []
            "writeConcernErrors" : [] }

       The index field in the upserted array is the 0-based index of  the  upsert  operation;  in
       this  example,  the  sixth  operation  of the overall bulk operation was an upsert, so its
       index is 5.

   Unordered Bulk Write Operations
       Unordered bulk write operations are batched and sent to  the  server  in  arbitrary  order
       where  they  may  be  executed  in  parallel. Any errors that occur are reported after all
       operations are attempted.

       In the next example the first and third operations fail due to the  unique  constraint  on
       _id. Since we are doing unordered execution the second and fourth operations succeed.

       bulk3.c

          #include <assert.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          bulk3 (mongoc_collection_t *collection)
          {
             bson_t opts = BSON_INITIALIZER;
             mongoc_bulk_operation_t *bulk;
             bson_error_t error;
             bson_t *query;
             bson_t *doc;
             bson_t reply;
             char *str;
             bool ret;

             /* false indicates unordered */
             BSON_APPEND_BOOL (&opts, "ordered", false);
             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
             bson_destroy (&opts);

             /* Add a document */
             doc = BCON_NEW ("_id", BCON_INT32 (1));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             /* remove {_id: 2} */
             query = BCON_NEW ("_id", BCON_INT32 (2));
             mongoc_bulk_operation_remove_one (bulk, query);
             bson_destroy (query);

             /* insert {_id: 3} */
             doc = BCON_NEW ("_id", BCON_INT32 (3));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             /* replace {_id:4} {'i': 1} */
             query = BCON_NEW ("_id", BCON_INT32 (4));
             doc = BCON_NEW ("i", BCON_INT32 (1));
             mongoc_bulk_operation_replace_one (bulk, query, doc, false);
             bson_destroy (query);
             bson_destroy (doc);

             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                printf ("Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             mongoc_bulk_operation_destroy (bulk);
             bson_destroy (&opts);
          }

          int
          main (void)
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             const char *uri_string = "mongodb://localhost/?appname=bulk3-example";
             mongoc_uri_t *uri;
             bson_error_t error;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             collection = mongoc_client_get_collection (client, "test", "test");

             bulk3 (collection);

             mongoc_uri_destroy (uri);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       Example reply document:

          { "nInserted"    : 0,
            "nMatched"     : 1,
            "nModified"    : 1,
            "nRemoved"     : 1,
            "nUpserted"    : 0,
            "writeErrors"  : [
              { "index"  : 0,
                "code"   : 11000,
                "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" },
              { "index"  : 2,
                "code"   : 11000,
                "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ],
            "writeConcernErrors" : [] }

          Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }

       The bson_error_t domain is MONGOC_ERROR_COMMAND and its code is 11000.

   Bulk Operation Bypassing Document Validation
       This feature is only available when using MongoDB 3.2 and later.

       By default bulk operations are validated against the schema, if any is defined. In certain
       cases however it may be necessary to bypass the document validation.

       bulk5.c

          #include <assert.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          bulk5_fail (mongoc_collection_t *collection)
          {
             mongoc_bulk_operation_t *bulk;
             bson_error_t error;
             bson_t *doc;
             bson_t reply;
             char *str;
             bool ret;

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);

             /* Two inserts */
             doc = BCON_NEW ("_id", BCON_INT32 (31));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             doc = BCON_NEW ("_id", BCON_INT32 (32));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             /* The above documents do not comply to the schema validation rules
              * we created previously, so this will result in an error */
             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                printf ("Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             mongoc_bulk_operation_destroy (bulk);
          }

          static void
          bulk5_success (mongoc_collection_t *collection)
          {
             mongoc_bulk_operation_t *bulk;
             bson_error_t error;
             bson_t *doc;
             bson_t reply;
             char *str;
             bool ret;

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);

             /* Allow this document to bypass document validation.
              * NOTE: When authentication is enabled, the authenticated user must have
              * either the "dbadmin" or "restore" roles to bypass document validation */
             mongoc_bulk_operation_set_bypass_document_validation (bulk, true);

             /* Two inserts */
             doc = BCON_NEW ("_id", BCON_INT32 (31));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             doc = BCON_NEW ("_id", BCON_INT32 (32));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                printf ("Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             mongoc_bulk_operation_destroy (bulk);
          }

          int
          main (void)
          {
             bson_t *options;
             bson_error_t error;
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             mongoc_database_t *database;
             const char *uri_string = "mongodb://localhost/?appname=bulk5-example";
             mongoc_uri_t *uri;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             database = mongoc_client_get_database (client, "testasdf");

             /* Create schema validator */
             options = BCON_NEW (
                "validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}");
             collection =
                mongoc_database_create_collection (database, "collname", options, &error);

             if (collection) {
                bulk5_fail (collection);
                bulk5_success (collection);
                mongoc_collection_destroy (collection);
             } else {
                fprintf (stderr, "Couldn't create collection: '%s'\n", error.message);
             }

             bson_free (options);
             mongoc_uri_destroy (uri);
             mongoc_database_destroy (database);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       Running the above example will result in:

          { "nInserted" : 0,
            "nMatched" : 0,
            "nModified" : 0,
            "nRemoved" : 0,
            "nUpserted" : 0,
            "writeErrors" : [
              { "index" : 0,
                "code" : 121,
                "errmsg" : "Document failed validation" } ] }

          Error: Document failed validation

          { "nInserted" : 2,
            "nMatched" : 0,
            "nModified" : 0,
            "nRemoved" : 0,
            "nUpserted" : 0,
            "writeErrors" : [] }

       The bson_error_t domain is MONGOC_ERROR_COMMAND.

   Bulk Operation Write Concerns
       By default bulk operations are executed with the write_concern of the collection they  are
       executed    against.    A    custom    write    concern    can    be    passed    to   the
       mongoc_collection_create_bulk_operation_with_opts() method.  Write  concern  errors  (e.g.
       wtimeout)  will  be  reported  after all operations are attempted, regardless of execution
       order.

       bulk4.c

          #include <assert.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          bulk4 (mongoc_collection_t *collection)
          {
             bson_t opts = BSON_INITIALIZER;
             mongoc_write_concern_t *wc;
             mongoc_bulk_operation_t *bulk;
             bson_error_t error;
             bson_t *doc;
             bson_t reply;
             char *str;
             bool ret;

             wc = mongoc_write_concern_new ();
             mongoc_write_concern_set_w (wc, 4);
             mongoc_write_concern_set_wtimeout_int64 (wc, 100); /* milliseconds */
             mongoc_write_concern_append (wc, &opts);

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);

             /* Two inserts */
             doc = BCON_NEW ("_id", BCON_INT32 (10));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             doc = BCON_NEW ("_id", BCON_INT32 (11));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                printf ("Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             mongoc_bulk_operation_destroy (bulk);
             mongoc_write_concern_destroy (wc);
             bson_destroy (&opts);
          }

          int
          main (void)
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             const char *uri_string = "mongodb://localhost/?appname=bulk4-example";
             mongoc_uri_t *uri;
             bson_error_t error;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             collection = mongoc_client_get_collection (client, "test", "test");

             bulk4 (collection);

             mongoc_uri_destroy (uri);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       Example reply document and error message:

          { "nInserted"    : 2,
            "nMatched"     : 0,
            "nModified"    : 0,
            "nRemoved"     : 0,
            "nUpserted"    : 0,
            "writeErrors"  : [],
            "writeConcernErrors" : [
              { "code"   : 64,
                "errmsg" : "waiting for replication timed out" }
          ] }

          Error: waiting for replication timed out

       The bson_error_t domain is MONGOC_ERROR_WRITE_CONCERN if there are  write  concern  errors
       and no write errors. Write errors indicate failed operations, so they take precedence over
       write concern errors, which mean merely that the write concern is not satisfied yet.

   Setting Collation Order
       This feature is only available when using MongoDB 3.4 and later.

       bulk-collation.c

          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          bulk_collation (mongoc_collection_t *collection)
          {
             mongoc_bulk_operation_t *bulk;
             bson_t *opts;
             bson_t *doc;
             bson_t *selector;
             bson_t *update;
             bson_error_t error;
             bson_t reply;
             char *str;
             uint32_t ret;

             /* insert {_id: "one"} and {_id: "One"} */
             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
             doc = BCON_NEW ("_id", BCON_UTF8 ("one"));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             doc = BCON_NEW ("_id", BCON_UTF8 ("One"));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             /* "One" normally sorts before "one"; make "one" come first */
             opts = BCON_NEW ("collation",
                              "{",
                              "locale",
                              BCON_UTF8 ("en_US"),
                              "caseFirst",
                              BCON_UTF8 ("lower"),
                              "}");

             /* set x=1 on the document with _id "One", which now sorts after "one" */
             update = BCON_NEW ("$set", "{", "x", BCON_INT64 (1), "}");
             selector = BCON_NEW ("_id", "{", "$gt", BCON_UTF8 ("one"), "}");
             mongoc_bulk_operation_update_one_with_opts (
                bulk, selector, update, opts, &error);

             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                printf ("Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             bson_destroy (update);
             bson_destroy (selector);
             bson_destroy (opts);
             mongoc_bulk_operation_destroy (bulk);
          }

          int
          main (void)
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             const char *uri_string = "mongodb://localhost/?appname=bulk-collation";
             mongoc_uri_t *uri;
             bson_error_t error;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             collection = mongoc_client_get_collection (client, "db", "collection");
             bulk_collation (collection);

             mongoc_uri_destroy (uri);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       Running the above example will result in:

          { "nInserted" : 2,
             "nMatched" : 1,
             "nModified" : 1,
             "nRemoved" : 0,
             "nUpserted" : 0,
             "writeErrors" : [  ]
          }

   Unacknowledged Bulk Writes
       Set "w" to zero for an unacknowledged write. The driver sends unacknowledged writes  using
       the legacy opcodes OP_INSERT, OP_UPDATE, and OP_DELETE.

       bulk6.c

          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          bulk6 (mongoc_collection_t *collection)
          {
             bson_t opts = BSON_INITIALIZER;
             mongoc_write_concern_t *wc;
             mongoc_bulk_operation_t *bulk;
             bson_error_t error;
             bson_t *doc;
             bson_t *selector;
             bson_t reply;
             char *str;
             bool ret;

             wc = mongoc_write_concern_new ();
             mongoc_write_concern_set_w (wc, 0);
             mongoc_write_concern_append (wc, &opts);

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);

             doc = BCON_NEW ("_id", BCON_INT32 (10));
             mongoc_bulk_operation_insert (bulk, doc);
             bson_destroy (doc);

             selector = BCON_NEW ("_id", BCON_INT32 (11));
             mongoc_bulk_operation_remove_one (bulk, selector);
             bson_destroy (selector);

             ret = mongoc_bulk_operation_execute (bulk, &reply, &error);

             str = bson_as_canonical_extended_json (&reply, NULL);
             printf ("%s\n", str);
             bson_free (str);

             if (!ret) {
                printf ("Error: %s\n", error.message);
             }

             bson_destroy (&reply);
             mongoc_bulk_operation_destroy (bulk);
             mongoc_write_concern_destroy (wc);
             bson_destroy (&opts);
          }

          int
          main (void)
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             const char *uri_string = "mongodb://localhost/?appname=bulk6-example";
             mongoc_uri_t *uri;
             bson_error_t error;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             collection = mongoc_client_get_collection (client, "test", "test");

             bulk6 (collection);

             mongoc_uri_destroy (uri);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       The reply document is empty:

          { }

   Further Reading
       See  the  Driver  Bulk  API  Spec,  which  describes bulk write operations for all MongoDB
       drivers.

   Aggregation Framework Examples
       This document provides a number of practical examples that display the capabilities of the
       aggregation framework.

       The  Aggregations using the Zip Codes Data Set examples uses a publicly available data set
       of all zipcodes and populations in  the  United  States.  These  data  are  available  at:
       zips.json.

   Requirements
       Let's check if everything is installed.

       Use the following command to load zips.json data set into mongod instance:

          $ mongoimport --drop -d test -c zipcodes zips.json

       Let's use the MongoDB shell to verify that everything was imported successfully.

          $ mongo test
          connecting to: test
          > db.zipcodes.count()
          29467
          > db.zipcodes.findOne()
          {
                "_id" : "35004",
                "city" : "ACMAR",
                "loc" : [
                        -86.51557,
                        33.584132
                ],
                "pop" : 6055,
                "state" : "AL"
          }

   Aggregations using the Zip Codes Data Set
       Each document in this collection has the following form:

          {
            "_id" : "35004",
            "city" : "Acmar",
            "state" : "AL",
            "pop" : 6055,
            "loc" : [-86.51557, 33.584132]
          }

       In these documents:

       • The _id field holds the zipcode as a string.

       • The city field holds the city name.

       • The state field holds the two letter state abbreviation.

       • The pop field holds the population.

       • The loc field holds the location as a [latitude, longitude] array.

   States with Populations Over 10 Million
       To get all states with a population greater than 10 million, use the following aggregation
       pipeline:

       aggregation1.c

          #include <mongoc/mongoc.h>
          #include <stdio.h>

          static void
          print_pipeline (mongoc_collection_t *collection)
          {
             mongoc_cursor_t *cursor;
             bson_error_t error;
             const bson_t *doc;
             bson_t *pipeline;
             char *str;

             pipeline = BCON_NEW ("pipeline",
                                  "[",
                                  "{",
                                  "$group",
                                  "{",
                                  "_id",
                                  "$state",
                                  "total_pop",
                                  "{",
                                  "$sum",
                                  "$pop",
                                  "}",
                                  "}",
                                  "}",
                                  "{",
                                  "$match",
                                  "{",
                                  "total_pop",
                                  "{",
                                  "$gte",
                                  BCON_INT32 (10000000),
                                  "}",
                                  "}",
                                  "}",
                                  "]");

             cursor = mongoc_collection_aggregate (
                collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL);

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_canonical_extended_json (doc, NULL);
                printf ("%s\n", str);
                bson_free (str);
             }

             if (mongoc_cursor_error (cursor, &error)) {
                fprintf (stderr, "Cursor Failure: %s\n", error.message);
             }

             mongoc_cursor_destroy (cursor);
             bson_destroy (pipeline);
          }

          int
          main (void)
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             const char *uri_string =
                "mongodb://localhost:27017/?appname=aggregation-example";
             mongoc_uri_t *uri;
             bson_error_t error;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             collection = mongoc_client_get_collection (client, "test", "zipcodes");

             print_pipeline (collection);

             mongoc_uri_destroy (uri);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       You should see a result like the following:

          { "_id" : "PA", "total_pop" : 11881643 }
          { "_id" : "OH", "total_pop" : 10847115 }
          { "_id" : "NY", "total_pop" : 17990455 }
          { "_id" : "FL", "total_pop" : 12937284 }
          { "_id" : "TX", "total_pop" : 16986510 }
          { "_id" : "IL", "total_pop" : 11430472 }
          { "_id" : "CA", "total_pop" : 29760021 }

       The above aggregation pipeline is build from two pipeline operators: $group and $match.

       The $group pipeline operator requires _id  field  where  we  specify  grouping;  remaining
       fields  specify  how to generate composite value and must use one of the group aggregation
       functions: $addToSet, $first, $last, $max, $min, $avg, $push, $sum.  The  $match  pipeline
       operator syntax is the same as the read operation query syntax.

       The  $group process reads all documents and for each state it creates a separate document,
       for example:

          { "_id" : "WA", "total_pop" : 4866692 }

       The total_pop field uses the $sum aggregation function to sum the values of all pop fields
       in the source documents.

       Documents  created  by  $group  are  piped to the $match pipeline operator. It returns the
       documents with the value of total_pop field greater than or equal to 10 million.

   Average City Population by State
       To get the first three states with the greatest  average  population  per  city,  use  the
       following aggregation:

          pipeline = BCON_NEW ("pipeline", "[",
             "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}",
             "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}",
             "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}",
             "{", "$limit", BCON_INT32 (3) "}",
          "]");

       This aggregate pipeline produces:

          { "_id" : "DC", "avg_city_pop" : 303450.0 }
          { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
          { "_id" : "CA", "avg_city_pop" : 27735.341099720412 }

       The  above  aggregation pipeline is build from three pipeline operators: $group, $sort and
       $limit.

       The first $group operator creates the following documents:

          { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 }

       Note, that the $group operator can't use nested documents except the _id field.

       The second $group uses these documents to create the following documents:

          { "_id" : "FL", "avg_city_pop" : 27942.29805615551 }

       These documents are sorted by the avg_city_pop field in  descending  order.  Finally,  the
       $limit pipeline operator returns the first 3 documents from the sorted set.

   "distinct" and "mapReduce"
       This  document  provides  some practical, simple, examples to demonstrate the distinct and
       mapReduce commands.

   Setup
       First we'll write some code to insert sample data:

       doc-common-insert.c

          /* Don't try to compile this file on its own. It's meant to be #included
             by example code */

          /* Insert some sample data */
          bool
          insert_data (mongoc_collection_t *collection)
          {
             mongoc_bulk_operation_t *bulk;
             enum N { ndocs = 4 };
             bson_t *docs[ndocs];
             bson_error_t error;
             int i = 0;
             bool ret;

             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);

             docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
             docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
             docs[2] = BCON_NEW (
                "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
             docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");

             for (i = 0; i < ndocs; i++) {
                mongoc_bulk_operation_insert (bulk, docs[i]);
                bson_destroy (docs[i]);
                docs[i] = NULL;
             }

             ret = mongoc_bulk_operation_execute (bulk, NULL, &error);

             if (!ret) {
                fprintf (stderr, "Error inserting data: %s\n", error.message);
             }

             mongoc_bulk_operation_destroy (bulk);
             return ret;
          }

          /* A helper which we'll use a lot later on */
          void
          print_res (const bson_t *reply)
          {
             char *str;
             BSON_ASSERT (reply);
             str = bson_as_canonical_extended_json (reply, NULL);
             printf ("%s\n", str);
             bson_free (str);
          }

   "distinct" command
       This is how to use the distinct command to get the distinct values of x which are  greater
       than 1:

       distinct.c

          bool
          distinct (mongoc_database_t *database)
          {
             bson_t *command;
             bson_t reply;
             bson_error_t error;
             bool res;
             bson_iter_t iter;
             bson_iter_t array_iter;
             double val;

             command = BCON_NEW ("distinct",
                                 BCON_UTF8 (COLLECTION_NAME),
                                 "key",
                                 BCON_UTF8 ("x"),
                                 "query",
                                 "{",
                                 "x",
                                 "{",
                                 "$gt",
                                 BCON_DOUBLE (1.0),
                                 "}",
                                 "}");
             res =
                mongoc_database_command_simple (database, command, NULL, &reply, &error);
             if (!res) {
                fprintf (stderr, "Error with distinct: %s\n", error.message);
                goto cleanup;
             }

             /* Do something with reply (in this case iterate through the values) */
             if (!(bson_iter_init_find (&iter, &reply, "values") &&
                   BSON_ITER_HOLDS_ARRAY (&iter) &&
                   bson_iter_recurse (&iter, &array_iter))) {
                fprintf (stderr, "Couldn't extract \"values\" field from response\n");
                goto cleanup;
             }

             while (bson_iter_next (&array_iter)) {
                if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) {
                   val = bson_iter_double (&array_iter);
                   printf ("Next double: %f\n", val);
                }
             }

          cleanup:
             /* cleanup */
             bson_destroy (command);
             bson_destroy (&reply);
             return res;
          }

   "mapReduce" - basic example
       A  simple  example  using  the  map  reduce  framework.  It  simply  adds up the number of
       occurrences of each "tag".

       First define the map and reduce functions:

       constants.c

          const char *const COLLECTION_NAME = "things";

          /* Our map function just emits a single (key, 1) pair for each tag
             in the array: */
          const char *const MAPPER = "function () {"
                                     "this.tags.forEach(function(z) {"
                                     "emit(z, 1);"
                                     "});"
                                     "}";

          /* The reduce function sums over all of the emitted values for a
             given key: */
          const char *const REDUCER = "function (key, values) {"
                                      "var total = 0;"
                                      "for (var i = 0; i < values.length; i++) {"
                                      "total += values[i];"
                                      "}"
                                      "return total;"
                                      "}";
          /* Note We can't just return values.length as the reduce function
             might be called iteratively on the results of other reduce
             steps. */

       Run   the    mapReduce    command.    Use    the    generic    command    helpers    (e.g.
       mongoc_database_command_simple()).     Do    not    the   read   command   helpers   (e.g.
       mongoc_database_read_command_with_opts())  because  they  are  considered  retryable  read
       operations.  If  retryable  reads  are  enabled,  those  operations  will  retry once on a
       retryable error, giving undesirable behavior for mapReduce.

       map-reduce-basic.c

          bool
          map_reduce_basic (mongoc_database_t *database)
          {
             bson_t reply;
             bson_t *command;
             bool res;
             bson_error_t error;
             mongoc_cursor_t *cursor;
             const bson_t *doc;

             bool query_done = false;

             const char *out_collection_name = "outCollection";
             mongoc_collection_t *out_collection;

             /* Empty find query */
             bson_t find_query = BSON_INITIALIZER;

             /* Construct the mapReduce command */

             /* Other arguments can also be specified here, like "query" or
                "limit" and so on */
             command = BCON_NEW ("mapReduce",
                                 BCON_UTF8 (COLLECTION_NAME),
                                 "map",
                                 BCON_CODE (MAPPER),
                                 "reduce",
                                 BCON_CODE (REDUCER),
                                 "out",
                                 BCON_UTF8 (out_collection_name));
             res =
                mongoc_database_command_simple (database, command, NULL, &reply, &error);

             if (!res) {
                fprintf (stderr, "MapReduce failed: %s\n", error.message);
                goto cleanup;
             }

             /* Do something with the reply (it doesn't contain the mapReduce results) */
             print_res (&reply);

             /* Now we'll query outCollection to see what the results are */
             out_collection =
                mongoc_database_get_collection (database, out_collection_name);
             cursor = mongoc_collection_find_with_opts (
                out_collection, &find_query, NULL, NULL);
             query_done = true;

             /* Do something with the results */
             while (mongoc_cursor_next (cursor, &doc)) {
                print_res (doc);
             }

             if (mongoc_cursor_error (cursor, &error)) {
                fprintf (stderr, "ERROR: %s\n", error.message);
                res = false;
                goto cleanup;
             }

          cleanup:
             /* cleanup */
             if (query_done) {
                mongoc_cursor_destroy (cursor);
                mongoc_collection_destroy (out_collection);
             }

             bson_destroy (&reply);
             bson_destroy (command);

             return res;
          }

   "mapReduce" - more complicated example
       You must have replica set running for this.

       In this example we contact a secondary in the replica set and do an "inline"  map  reduce,
       so the results are returned immediately:

       map-reduce-advanced.c

          bool
          map_reduce_advanced (mongoc_database_t *database)
          {
             bson_t *command;
             bson_error_t error;
             bool res = true;
             mongoc_cursor_t *cursor;
             mongoc_read_prefs_t *read_pref;
             const bson_t *doc;

             /* Construct the mapReduce command */
             /* Other arguments can also be specified here, like "query" or "limit"
                and so on */

             /* Read the results inline from a secondary replica */
             command = BCON_NEW ("mapReduce",
                                 BCON_UTF8 (COLLECTION_NAME),
                                 "map",
                                 BCON_CODE (MAPPER),
                                 "reduce",
                                 BCON_CODE (REDUCER),
                                 "out",
                                 "{",
                                 "inline",
                                 "1",
                                 "}");

             read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
             cursor = mongoc_database_command (
                database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref);

             /* Do something with the results */
             while (mongoc_cursor_next (cursor, &doc)) {
                print_res (doc);
             }

             if (mongoc_cursor_error (cursor, &error)) {
                fprintf (stderr, "ERROR: %s\n", error.message);
                res = false;
             }

             mongoc_cursor_destroy (cursor);
             mongoc_read_prefs_destroy (read_pref);
             bson_destroy (command);

             return res;
          }

   Running the Examples
       Here's how to run the example code

       basic-aggregation.c

          /*
           * Copyright 2016 MongoDB, Inc.
           *
           * Licensed under the Apache License, Version 2.0 (the "License");
           * you may not use this file except in compliance with the License.
           * You may obtain a copy of the License at
           *
           *   http://www.apache.org/licenses/LICENSE-2.0
           *
           * Unless required by applicable law or agreed to in writing, software
           * distributed under the License is distributed on an "AS IS" BASIS,
           * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           * See the License for the specific language governing permissions and
           * limitations under the License.
           */

          #include <mongoc/mongoc.h>
          #include <stdio.h>

          #include "constants.c"

          #include "../doc-common-insert.c"
          #include "distinct.c"
          #include "map-reduce-basic.c"
          #include "map-reduce-advanced.c"

          int
          main (int argc, char *argv[])
          {
             mongoc_database_t *database = NULL;
             mongoc_client_t *client = NULL;
             mongoc_collection_t *collection = NULL;
             mongoc_uri_t *uri = NULL;
             bson_error_t error;
             char *host_and_port = NULL;
             int exit_code = EXIT_FAILURE;

             if (argc != 2) {
                fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]);
                fprintf (stderr,
                         "the connection string can be of the following forms:\n");
                fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
                fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
                fprintf (stderr,
                         "mongodb://user:pass@localhost:27017\t"
                         "local machine on port 27017, and authenticate with username "
                         "user and password pass\n");
                return exit_code;
             }

             mongoc_init ();

             if (strncmp (argv[1], "mongodb://", 10) == 0) {
                host_and_port = bson_strdup (argv[1]);
             } else {
                host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
             }

             uri = mongoc_uri_new_with_error (host_and_port, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         host_and_port,
                         error.message);
                goto cleanup;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                goto cleanup;
             }

             mongoc_client_set_error_api (client, 2);
             database = mongoc_client_get_database (client, "test");
             collection = mongoc_database_get_collection (database, COLLECTION_NAME);

             printf ("Inserting data\n");
             if (!insert_data (collection)) {
                goto cleanup;
             }

             printf ("distinct\n");
             if (!distinct (database)) {
                goto cleanup;
             }

             printf ("map reduce\n");
             if (!map_reduce_basic (database)) {
                goto cleanup;
             }

             printf ("more complicated map reduce\n");
             if (!map_reduce_advanced (database)) {
                goto cleanup;
             }

             exit_code = EXIT_SUCCESS;

          cleanup:
             if (collection) {
                mongoc_collection_destroy (collection);
             }

             if (database) {
                mongoc_database_destroy (database);
             }

             if (client) {
                mongoc_client_destroy (client);
             }

             if (uri) {
                mongoc_uri_destroy (uri);
             }

             if (host_and_port) {
                bson_free (host_and_port);
             }

             mongoc_cleanup ();
             return exit_code;
          }

       If  you  want to try the advanced map reduce example with a secondary, start a replica set
       (instructions for how to do this can be found here).

       Otherwise, just start an instance of MongoDB:

          $ mongod

       Now compile and run the example program:

          $ cd examples/basic_aggregation/
          $ gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0)
          $ ./agg-example localhost

          Inserting data
          distinct
          Next double: 2.000000
          Next double: 3.000000
          map reduce
          { "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
          { "_id" : "cat", "value" : 63 }
          { "_id" : "dog", "value" : 42 }
          { "_id" : "mouse", "value" : 21 }
          more complicated map reduce
          { "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 }

   Using libmongoc in a Microsoft Visual Studio project
       Download  and  install  libmongoc  on  your  system,  then  open  Visual  Studio,   select
       "File→New→Project...", and create a new Win32 Console Application.  [image]

       Remember to switch the platform from 32-bit to 64-bit: [image]

       Right-click  on your console application in the Solution Explorer and select "Properties".
       Choose to edit properties for "All Configurations", expand the "C/C++" options and  choose
       "General". Add to the "Additional Include Directories" these paths:

          C:\mongo-c-driver\include\libbson-1.0
          C:\mongo-c-driver\include\libmongoc-1.0
       [image]

       (If  you  chose  a different $PREFIX when you installed mongo-c-driver, your include paths
       will be different.)

       Also in the Properties dialog, expand the "Linker" options and choose "Input", and add  to
       the "Additional Dependencies" these libraries:

          C:\mongo-c-driver\lib\bson-1.0.lib
          C:\mongo-c-driver\lib\mongoc-1.0.lib
       [image]

       Adding  these libraries as dependencies provides linker symbols to build your application,
       but to actually run it, libbson's and libmongoc's DLLs must be in  your  executable  path.
       Select "Debugging" in the Properties dialog, and set the "Environment" option to:

          PATH=c:/mongo-c-driver/bin
       [image]

       Finally, include "mongoc/mongoc.h" in your project's "stdafx.h":

          #include <mongoc/mongoc.h>

   Static linking
       Following  the  instructions  above,  you  have dynamically linked your application to the
       libbson and libmongoc DLLs. This is  usually  the  right  choice.  If  you  want  to  link
       statically  instead,  update  your "Additional Dependencies" list by removing bson-1.0.lib
       and mongoc-1.0.lib and replacing them with these libraries:

          C:\mongo-c-driver\lib\bson-static-1.0.lib
          C:\mongo-c-driver\lib\mongoc-static-1.0.lib
          ws2_32.lib
          Secur32.lib
          Crypt32.lib
          BCrypt.lib
       [image]

       (To explain the purpose of each library: bson-static-1.0.lib and mongoc-static-1.0.lib are
       static  archives  of  the  driver  code. The socket library ws2_32 is required by libbson,
       which uses the socket routine gethostname  to  help  guarantee  ObjectId  uniqueness.  The
       BCrypt  library  is  used  by  libmongoc  for  TLS connections to MongoDB, and Secur32 and
       Crypt32 are required for enterprise authentication methods like Kerberos.)

       Finally,  define  two  preprocessor  symbols  before  including  mongoc/mongoc.h  in  your
       stdafx.h:

          #define BSON_STATIC
          #define MONGOC_STATIC
          #include <mongoc/mongoc.h>

       Making these changes to your project is only required for static linking; for most people,
       the dynamic-linking instructions above are preferred.

   Next Steps
       Now you can build and debug applications in Visual Studio that use libbson and  libmongoc.
       Proceed to Making a Connection in the tutorial to learn how connect to MongoDB and perform
       operations.

   Manage Collection Indexes
       To       create       indexes       on       a       MongoDB        collection,        use
       mongoc_collection_create_indexes_with_opts():

          // `keys` represents an ascending index on field `x`.
          bson_t *keys = BCON_NEW ("x", BCON_INT32 (1));
          mongoc_index_model_t *im = mongoc_index_model_new (keys, NULL /* opts */);
          if (mongoc_collection_create_indexes_with_opts (
                 coll, &im, 1, NULL /* opts */, NULL /* reply */, &error)) {
             printf ("Successfully created index\n");
          } else {
             bson_destroy (keys);
             HANDLE_ERROR ("Failed to create index: %s", error.message);
          }
          bson_destroy (keys);

       To list indexes, use mongoc_collection_find_indexes_with_opts():

          mongoc_cursor_t *cursor =
             mongoc_collection_find_indexes_with_opts (coll, NULL /* opts */);
          printf ("Listing indexes:\n");
          const bson_t *got;
          while (mongoc_cursor_next (cursor, &got)) {
             char *got_str = bson_as_canonical_extended_json (got, NULL);
             printf ("  %s\n", got_str);
             bson_free (got_str);
          }
          if (mongoc_cursor_error (cursor, &error)) {
             mongoc_cursor_destroy (cursor);
             HANDLE_ERROR ("Failed to list indexes: %s", error.message);
          }
          mongoc_cursor_destroy (cursor);

       To  drop  an  index,  use  mongoc_collection_drop_index_with_opts(). The index name may be
       obtained from the keys document with mongoc_collection_keys_to_index_string():

          bson_t *keys = BCON_NEW ("x", BCON_INT32 (1));
          char *index_name = mongoc_collection_keys_to_index_string (keys);
          if (mongoc_collection_drop_index_with_opts (
                 coll, index_name, NULL /* opts */, &error)) {
             printf ("Successfully dropped index\n");
          } else {
             bson_free (index_name);
             bson_destroy (keys);
             HANDLE_ERROR ("Failed to drop index: %s", error.message);
          }
          bson_free (index_name);
          bson_destroy (keys);

       For a full example, see example-manage-collection-indexes.c.

   Manage Atlas Search Indexes
       To create an Atlas Search Index, use the createSearchIndexes command:

          bson_t cmd;
          // Create command.
          {
             char *cmd_str = bson_strdup_printf (
                BSON_STR ({
                   "createSearchIndexes" : "%s",
                   "indexes" : [ {
                      "definition" : {"mappings" : {"dynamic" : false}},
                      "name" : "test-index"
                   } ]
                }),
                collname);
             ASSERT (bson_init_from_json (&cmd, cmd_str, -1, &error));
             bson_free (cmd_str);
          }
          if (!mongoc_collection_command_simple (
                 coll, &cmd, NULL /* read_prefs */, NULL /* reply */, &error)) {
             bson_destroy (&cmd);
             HANDLE_ERROR ("Failed to run createSearchIndexes: %s", error.message);
          }
          printf ("Created index: \"test-index\"\n");
          bson_destroy (&cmd);

       To list Atlas Search Indexes, use the $listSearchIndexes aggregation stage:

          const char *pipeline_str =
             BSON_STR ({"pipeline" : [ {"$listSearchIndexes" : {}} ]});
          bson_t pipeline;
          ASSERT (bson_init_from_json (&pipeline, pipeline_str, -1, &error));
          mongoc_cursor_t *cursor =
             mongoc_collection_aggregate (coll,
                                          MONGOC_QUERY_NONE,
                                          &pipeline,
                                          NULL /* opts */,
                                          NULL /* read_prefs */);
          printf ("Listing indexes:\n");
          const bson_t *got;
          while (mongoc_cursor_next (cursor, &got)) {
             char *got_str = bson_as_canonical_extended_json (got, NULL);
             printf ("  %s\n", got_str);
             bson_free (got_str);
          }
          if (mongoc_cursor_error (cursor, &error)) {
             bson_destroy (&pipeline);
             mongoc_cursor_destroy (cursor);
             HANDLE_ERROR ("Failed to run $listSearchIndexes: %s", error.message);
          }
          bson_destroy (&pipeline);
          mongoc_cursor_destroy (cursor);

       To update an Atlas Search Index, use the updateSearchIndex command:

          bson_t cmd;
          // Create command.
          {
             char *cmd_str = bson_strdup_printf (
                BSON_STR ({
                   "updateSearchIndex" : "%s",
                   "definition" : {"mappings" : {"dynamic" : true}},
                   "name" : "test-index"
                }),
                collname);
             ASSERT (bson_init_from_json (&cmd, cmd_str, -1, &error));
             bson_free (cmd_str);
          }
          if (!mongoc_collection_command_simple (
                 coll, &cmd, NULL /* read_prefs */, NULL /* reply */, &error)) {
             bson_destroy (&cmd);
             HANDLE_ERROR ("Failed to run updateSearchIndex: %s", error.message);
          }
          printf ("Updated index: \"test-index\"\n");
          bson_destroy (&cmd);

       To drop an Atlas Search Index, use the dropSearchIndex command:

          bson_t cmd;
          // Create command.
          {
             char *cmd_str = bson_strdup_printf (
                BSON_STR ({"dropSearchIndex" : "%s", "name" : "test-index"}),
                collname);
             ASSERT (bson_init_from_json (&cmd, cmd_str, -1, &error));
             bson_free (cmd_str);
          }
          if (!mongoc_collection_command_simple (
                 coll, &cmd, NULL /* read_prefs */, NULL /* reply */, &error)) {
             bson_destroy (&cmd);
             HANDLE_ERROR ("Failed to run dropSearchIndex: %s", error.message);
          }
          printf ("Dropped index: \"test-index\"\n");
          bson_destroy (&cmd);

       For a full example, see example-manage-search-indexes.c.

   Aids for Debugging
   GDB
       This repository contains a .gdbinit file that contains helper functions to  aid  debugging
       of  data structures. GDB will load this file automatically if you have added the directory
       which contains the .gdbinit file to GDB's auto-load safe-path, and you start GDB from  the
       directory which holds the .gdbinit file.

       You can see the safe-path with show auto-load safe-path on a GDB prompt. You can configure
       it by setting it in ~/.gdbinit with:

          add-auto-load-safe-path /path/to/mongo-c-driver

       If you haven't added the path to  your  auto-load  safe-path,  or  start  GDB  in  another
       directory, load the file with:

          source path/to/mongo-c-driver/.gdbinit

       The  .gdbinit  file defines the printbson function, which shows the contents of a bson_t *
       variable.  If you have a local bson_t, then you must prefix the variable with a &.

       An example GDB session looks like:

          (gdb) printbson bson
          ALLOC [0x555556cd7310 + 0] (len=475)
          {
              'bool' : true,
              'int32' : NumberInt("42"),
              'int64' : NumberLong("3000000042"),
              'string' : "Stŕìñg",
              'objectId' : ObjectID("5A1442F3122D331C3C6757E1"),
              'utcDateTime' : UTCDateTime(1511277299031),
              'arrayOfInts' : [
                  '0' : NumberInt("1"),
                  '1' : NumberInt("2")
              ],
              'embeddedDocument' : {
                  'arrayOfStrings' : [
                      '0' : "one",
                      '1' : "two"
                  ],
                  'double' : 2.718280,
                  'notherDoc' : {
                      'true' : NumberInt("1"),
                      'false' : false
                  }
              },
              'binary' : Binary("02", "3031343532333637"),
              'regex' : Regex("@[a-z]+@", "im"),
              'null' : null,
              'js' : JavaScript("print foo"),
              'jsws' : JavaScript("print foo") with scope: {
                  'f' : NumberInt("42"),
                  'a' : [
                      '0' : 3.141593,
                      '1' : 2.718282
                  ]
              },
              'timestamp' : Timestamp(4294967295, 4294967295),
              'double' : 3.141593
          }

   LLDB
       The mongo-c-driver repository contains a script lldb_bson.py that can be imported into  an
       LLDB sessions and allows rich inspection of BSON values.

       NOTE:
          The lldb_bson.py module requires an LLDB with Python 3.8 or newer.

       To activate the script, import it from the LLDB command line:

          (lldb) command script import /path/to/mongo-c-driver/lldb_bson.py

       Upon success, the message lldb_bson is ready will be printed to the LLDB console.

       The  import  of  this  script  can be made automatic by adding the command to an .lldbinit
       file. For example: Create a file ~/.lldbinit containing:

          command script import /path/to/mongo-c-driver/lldb_bson.py

       The docstring at the top of  the  lldb_bson.py  file  contains  more  information  on  the
       capabilities of the module.

   Debug assertions
       To enable runtime debug assertions, configure with -DENABLE_DEBUG_ASSERTIONS=ON.

   In-Use Encryption
       In-Use Encryption consists of two features:

   Client-Side Field Level Encryption
       New  in MongoDB 4.2, Client-Side Field Level Encryption (also referred to as CSFLE) allows
       administrators and developers to encrypt specific data fields in addition to other MongoDB
       encryption features.

       With   CSFLE,   developers   can  encrypt  fields  client  side  without  any  server-side
       configuration or directives. CSFLE supports workloads where  applications  must  guarantee
       that  unauthorized  parties,  including  server  administrators, cannot read the encrypted
       data.

       Automatic encryption, where sensitive fields  in  commands  are  encrypted  automatically,
       requires  an Enterprise-only dependency for Query Analysis. See In-Use Encryption for more
       information.

       SEE ALSO:
          The MongoDB Manual for Client-Side Field Level Encryption

   Automatic Client-Side Field Level Encryption
       Automatic encryption is enabled by  calling  mongoc_client_enable_auto_encryption()  on  a
       mongoc_client_t.  The  following  examples  show  how to set up automatic encryption using
       mongoc_client_encryption_t to create a new encryption data key.

       NOTE:
          Automatic encryption requires MongoDB 4.2 enterprise or a MongoDB  4.2  Atlas  cluster.
          The  community  version of the server supports automatic decryption as well as Explicit
          Encryption.

   Providing Local Automatic Encryption Rules
       The following example shows how to specify automatic encryption rules using a  schema  map
       set  with mongoc_auto_encryption_opts_set_schema_map(). The automatic encryption rules are
       expressed using a strict subset of the JSON Schema syntax.

       Supplying a schema map provides more security than relying on JSON Schemas  obtained  from
       the  server. It protects against a malicious server advertising a false JSON Schema, which
       could trick the client into sending unencrypted data that should be encrypted.

       JSON Schemas supplied in the schema map only apply to  configuring  automatic  encryption.
       Other  validation  rules  in  the  JSON schema will not be enforced by the driver and will
       result in an error:

       client-side-encryption-schema-map.c

          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>

          #include "client-side-encryption-helpers.h"

          /* Helper method to create a new data key in the key vault, a schema to use that
           * key, and writes the schema to a file for later use. */
          static bool
          create_schema_file (bson_t *kms_providers,
                              const char *keyvault_db,
                              const char *keyvault_coll,
                              mongoc_client_t *keyvault_client,
                              bson_error_t *error)
          {
             mongoc_client_encryption_t *client_encryption = NULL;
             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
             bson_value_t datakey_id = {0};
             char *keyaltnames[] = {"mongoc_encryption_example_1"};
             bson_t *schema = NULL;
             char *schema_string = NULL;
             size_t schema_string_len;
             FILE *outfile = NULL;
             bool ret = false;

             client_encryption_opts = mongoc_client_encryption_opts_new ();
             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
                                                              kms_providers);
             mongoc_client_encryption_opts_set_keyvault_namespace (
                client_encryption_opts, keyvault_db, keyvault_coll);
             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
                                                                keyvault_client);

             client_encryption =
                mongoc_client_encryption_new (client_encryption_opts, error);
             if (!client_encryption) {
                goto fail;
             }

             /* Create a new data key and json schema for the encryptedField.
              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
              */
             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
             mongoc_client_encryption_datakey_opts_set_keyaltnames (
                datakey_opts, keyaltnames, 1);
             if (!mongoc_client_encryption_create_datakey (
                    client_encryption, "local", datakey_opts, &datakey_id, error)) {
                goto fail;
             }

             /* Create a schema describing that "encryptedField" is a string encrypted
              * with the newly created data key using deterministic encryption. */
             schema = BCON_NEW ("properties",
                                "{",
                                "encryptedField",
                                "{",
                                "encrypt",
                                "{",
                                "keyId",
                                "[",
                                BCON_BIN (datakey_id.value.v_binary.subtype,
                                          datakey_id.value.v_binary.data,
                                          datakey_id.value.v_binary.data_len),
                                "]",
                                "bsonType",
                                "string",
                                "algorithm",
                                MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
                                "}",
                                "}",
                                "}",
                                "bsonType",
                                "object");

             /* Use canonical JSON so that other drivers and tools will be
              * able to parse the MongoDB extended JSON file. */
             schema_string = bson_as_canonical_extended_json (schema, &schema_string_len);
             outfile = fopen ("jsonSchema.json", "w");
             if (0 == fwrite (schema_string, sizeof (char), schema_string_len, outfile)) {
                fprintf (stderr, "failed to write to file\n");
                goto fail;
             }

             ret = true;
          fail:
             mongoc_client_encryption_destroy (client_encryption);
             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
             mongoc_client_encryption_opts_destroy (client_encryption_opts);
             bson_free (schema_string);
             bson_destroy (schema);
             bson_value_destroy (&datakey_id);
             if (outfile) {
                fclose (outfile);
             }
             return ret;
          }

          /* This example demonstrates how to use automatic encryption with a client-side
           * schema map using the enterprise version of MongoDB */
          int
          main (void)
          {
          /* The collection used to store the encryption data keys. */
          #define KEYVAULT_DB "encryption"
          #define KEYVAULT_COLL "__libmongocTestKeyVault"
          /* The collection used to store the encrypted documents in this example. */
          #define ENCRYPTED_DB "test"
          #define ENCRYPTED_COLL "coll"

             int exit_status = EXIT_FAILURE;
             bool ret;
             uint8_t *local_masterkey = NULL;
             uint32_t local_masterkey_len;
             bson_t *kms_providers = NULL;
             bson_error_t error = {0};
             bson_t *index_keys = NULL;
             bson_t *index_opts = NULL;
             mongoc_index_model_t *index_model = NULL;
             bson_json_reader_t *reader = NULL;
             bson_t schema = BSON_INITIALIZER;
             bson_t *schema_map = NULL;

             /* The MongoClient used to access the key vault (keyvault_namespace). */
             mongoc_client_t *keyvault_client = NULL;
             mongoc_collection_t *keyvault_coll = NULL;
             mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
             mongoc_client_t *client = NULL;
             mongoc_collection_t *coll = NULL;
             bson_t *to_insert = NULL;
             mongoc_client_t *unencrypted_client = NULL;
             mongoc_collection_t *unencrypted_coll = NULL;

             mongoc_init ();

             /* Configure the master key. This must be the same master key that was used
              * to create the encryption key. */
             local_masterkey =
                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
             if (!local_masterkey || local_masterkey_len != 96) {
                fprintf (stderr,
                         "Specify LOCAL_MASTERKEY environment variable as a "
                         "secure random 96 byte hex value.\n");
                goto fail;
             }

             kms_providers = BCON_NEW ("local",
                                       "{",
                                       "key",
                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
                                       "}");

             /* Set up the key vault for this example. */
             keyvault_client = mongoc_client_new (
                "mongodb://localhost/?appname=client-side-encryption-keyvault");
             BSON_ASSERT (keyvault_client);

             keyvault_coll = mongoc_client_get_collection (
                keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
             mongoc_collection_drop (keyvault_coll, NULL);

             /* Create a unique index to ensure that two data keys cannot share the same
              * keyAltName. This is recommended practice for the key vault. */
             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
             index_opts = BCON_NEW ("unique",
                                    BCON_BOOL (true),
                                    "partialFilterExpression",
                                    "{",
                                    "keyAltNames",
                                    "{",
                                    "$exists",
                                    BCON_BOOL (true),
                                    "}",
                                    "}");
             index_model = mongoc_index_model_new (index_keys, index_opts);
             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
                                                               &index_model,
                                                               1,
                                                               NULL /* opts */,
                                                               NULL /* reply */,
                                                               &error);

             if (!ret) {
                goto fail;
             }

             /* Create a new data key and a schema using it for encryption. Save the
              * schema to the file jsonSchema.json */
             ret = create_schema_file (
                kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);

             if (!ret) {
                goto fail;
             }

             /* Load the JSON Schema and construct the local schema_map option. */
             reader = bson_json_reader_new_from_file ("jsonSchema.json", &error);
             if (!reader) {
                goto fail;
             }

             bson_json_reader_read (reader, &schema, &error);

             /* Construct the schema map, mapping the namespace of the collection to the
              * schema describing encryption. */
             schema_map =
                BCON_NEW (ENCRYPTED_DB "." ENCRYPTED_COLL, BCON_DOCUMENT (&schema));

             auto_encryption_opts = mongoc_auto_encryption_opts_new ();
             mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
                                                              keyvault_client);
             mongoc_auto_encryption_opts_set_keyvault_namespace (
                auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
             mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
                                                            kms_providers);
             mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts,
                                                         schema_map);

             client =
                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
             BSON_ASSERT (client);

             /* Enable automatic encryption. It will determine that encryption is
              * necessary from the schema map instead of relying on the server to provide
              * a schema. */
             ret = mongoc_client_enable_auto_encryption (
                client, auto_encryption_opts, &error);
             if (!ret) {
                goto fail;
             }

             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);

             /* Clear old data */
             mongoc_collection_drop (coll, NULL);

             to_insert = BCON_NEW ("encryptedField", "123456789");
             ret = mongoc_collection_insert_one (
                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
             if (!ret) {
                goto fail;
             }
             printf ("decrypted document: ");
             if (!print_one_document (coll, &error)) {
                goto fail;
             }
             printf ("\n");

             unencrypted_client = mongoc_client_new (
                "mongodb://localhost/?appname=client-side-encryption-unencrypted");
             BSON_ASSERT (unencrypted_client);

             unencrypted_coll = mongoc_client_get_collection (
                unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
             printf ("encrypted document: ");
             if (!print_one_document (unencrypted_coll, &error)) {
                goto fail;
             }
             printf ("\n");

             exit_status = EXIT_SUCCESS;
          fail:
             if (error.code) {
                fprintf (stderr, "error: %s\n", error.message);
             }

             bson_free (local_masterkey);
             bson_destroy (kms_providers);
             mongoc_collection_destroy (keyvault_coll);
             mongoc_index_model_destroy (index_model);
             bson_destroy (index_opts);
             bson_destroy (index_keys);
             bson_json_reader_destroy (reader);
             mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
             mongoc_collection_destroy (coll);
             mongoc_client_destroy (client);
             bson_destroy (to_insert);
             mongoc_collection_destroy (unencrypted_coll);
             mongoc_client_destroy (unencrypted_client);
             mongoc_client_destroy (keyvault_client);
             bson_destroy (&schema);
             bson_destroy (schema_map);
             mongoc_cleanup ();
             return exit_status;
          }

   Server-Side Field Level Encryption Enforcement
       The MongoDB 4.2 server supports using schema validation to enforce encryption of  specific
       fields  in a collection. This schema validation will prevent an application from inserting
       unencrypted values for any fields marked with the "encrypt" JSON schema keyword.

       The   following   example   shows   how   to   set   up   automatic    encryption    using
       mongoc_client_encryption_t  to  create  a  new encryption data key and create a collection
       with the necessary JSON Schema:

       client-side-encryption-server-schema.c

          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>

          #include "client-side-encryption-helpers.h"

          /* Helper method to create and return a JSON schema to use for encryption.
          The caller will use the returned schema for server-side encryption validation.
          */
          static bson_t *
          create_schema (bson_t *kms_providers,
                         const char *keyvault_db,
                         const char *keyvault_coll,
                         mongoc_client_t *keyvault_client,
                         bson_error_t *error)
          {
             mongoc_client_encryption_t *client_encryption = NULL;
             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
             bson_value_t datakey_id = {0};
             char *keyaltnames[] = {"mongoc_encryption_example_2"};
             bson_t *schema = NULL;

             client_encryption_opts = mongoc_client_encryption_opts_new ();
             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
                                                              kms_providers);
             mongoc_client_encryption_opts_set_keyvault_namespace (
                client_encryption_opts, keyvault_db, keyvault_coll);
             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
                                                                keyvault_client);

             client_encryption =
                mongoc_client_encryption_new (client_encryption_opts, error);
             if (!client_encryption) {
                goto fail;
             }

             /* Create a new data key and json schema for the encryptedField.
              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
              */
             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
             mongoc_client_encryption_datakey_opts_set_keyaltnames (
                datakey_opts, keyaltnames, 1);
             if (!mongoc_client_encryption_create_datakey (
                    client_encryption, "local", datakey_opts, &datakey_id, error)) {
                goto fail;
             }

             /* Create a schema describing that "encryptedField" is a string encrypted
              * with the newly created data key using deterministic encryption. */
             schema = BCON_NEW ("properties",
                                "{",
                                "encryptedField",
                                "{",
                                "encrypt",
                                "{",
                                "keyId",
                                "[",
                                BCON_BIN (datakey_id.value.v_binary.subtype,
                                          datakey_id.value.v_binary.data,
                                          datakey_id.value.v_binary.data_len),
                                "]",
                                "bsonType",
                                "string",
                                "algorithm",
                                MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
                                "}",
                                "}",
                                "}",
                                "bsonType",
                                "object");

          fail:
             mongoc_client_encryption_destroy (client_encryption);
             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
             mongoc_client_encryption_opts_destroy (client_encryption_opts);
             bson_value_destroy (&datakey_id);
             return schema;
          }

          /* This example demonstrates how to use automatic encryption with a server-side
           * schema using the enterprise version of MongoDB */
          int
          main (void)
          {
          /* The collection used to store the encryption data keys. */
          #define KEYVAULT_DB "encryption"
          #define KEYVAULT_COLL "__libmongocTestKeyVault"
          /* The collection used to store the encrypted documents in this example. */
          #define ENCRYPTED_DB "test"
          #define ENCRYPTED_COLL "coll"

             int exit_status = EXIT_FAILURE;
             bool ret;
             uint8_t *local_masterkey = NULL;
             uint32_t local_masterkey_len;
             bson_t *kms_providers = NULL;
             bson_error_t error = {0};
             bson_t *index_keys = NULL;
             bson_t *index_opts = NULL;
             mongoc_index_model_t *index_model = NULL;
             bson_json_reader_t *reader = NULL;
             bson_t *schema = NULL;

             /* The MongoClient used to access the key vault (keyvault_namespace). */
             mongoc_client_t *keyvault_client = NULL;
             mongoc_collection_t *keyvault_coll = NULL;
             mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
             mongoc_client_t *client = NULL;
             mongoc_collection_t *coll = NULL;
             bson_t *to_insert = NULL;
             mongoc_client_t *unencrypted_client = NULL;
             mongoc_collection_t *unencrypted_coll = NULL;
             bson_t *create_cmd = NULL;
             bson_t *create_cmd_opts = NULL;
             mongoc_write_concern_t *wc = NULL;

             mongoc_init ();

             /* Configure the master key. This must be the same master key that was used
              * to create
              * the encryption key. */
             local_masterkey =
                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
             if (!local_masterkey || local_masterkey_len != 96) {
                fprintf (stderr,
                         "Specify LOCAL_MASTERKEY environment variable as a "
                         "secure random 96 byte hex value.\n");
                goto fail;
             }

             kms_providers = BCON_NEW ("local",
                                       "{",
                                       "key",
                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
                                       "}");

             /* Set up the key vault for this example. */
             keyvault_client = mongoc_client_new (
                "mongodb://localhost/?appname=client-side-encryption-keyvault");
             BSON_ASSERT (keyvault_client);

             keyvault_coll = mongoc_client_get_collection (
                keyvault_client, KEYVAULT_DB, KEYVAULT_COLL);
             mongoc_collection_drop (keyvault_coll, NULL);

             /* Create a unique index to ensure that two data keys cannot share the same
              * keyAltName. This is recommended practice for the key vault. */
             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
             index_opts = BCON_NEW ("unique",
                                    BCON_BOOL (true),
                                    "partialFilterExpression",
                                    "{",
                                    "keyAltNames",
                                    "{",
                                    "$exists",
                                    BCON_BOOL (true),
                                    "}",
                                    "}");
             index_model = mongoc_index_model_new (index_keys, index_opts);
             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
                                                               &index_model,
                                                               1,
                                                               NULL /* opts */,
                                                               NULL /* reply */,
                                                               &error);

             if (!ret) {
                goto fail;
             }

             auto_encryption_opts = mongoc_auto_encryption_opts_new ();
             mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts,
                                                              keyvault_client);
             mongoc_auto_encryption_opts_set_keyvault_namespace (
                auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
             mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
                                                            kms_providers);
             schema = create_schema (
                kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error);

             if (!schema) {
                goto fail;
             }

             client =
                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
             BSON_ASSERT (client);

             ret = mongoc_client_enable_auto_encryption (
                client, auto_encryption_opts, &error);
             if (!ret) {
                goto fail;
             }

             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);

             /* Clear old data */
             mongoc_collection_drop (coll, NULL);

             /* Create the collection with the encryption JSON Schema. */
             create_cmd = BCON_NEW ("create",
                                    ENCRYPTED_COLL,
                                    "validator",
                                    "{",
                                    "$jsonSchema",
                                    BCON_DOCUMENT (schema),
                                    "}");
             wc = mongoc_write_concern_new ();
             mongoc_write_concern_set_wmajority (wc, 0);
             create_cmd_opts = bson_new ();
             mongoc_write_concern_append (wc, create_cmd_opts);
             ret = mongoc_client_command_with_opts (client,
                                                    ENCRYPTED_DB,
                                                    create_cmd,
                                                    NULL /* read prefs */,
                                                    create_cmd_opts,
                                                    NULL /* reply */,
                                                    &error);
             if (!ret) {
                goto fail;
             }

             to_insert = BCON_NEW ("encryptedField", "123456789");
             ret = mongoc_collection_insert_one (
                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
             if (!ret) {
                goto fail;
             }
             printf ("decrypted document: ");
             if (!print_one_document (coll, &error)) {
                goto fail;
             }
             printf ("\n");

             unencrypted_client = mongoc_client_new (
                "mongodb://localhost/?appname=client-side-encryption-unencrypted");
             BSON_ASSERT (unencrypted_client);

             unencrypted_coll = mongoc_client_get_collection (
                unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);
             printf ("encrypted document: ");
             if (!print_one_document (unencrypted_coll, &error)) {
                goto fail;
             }
             printf ("\n");

             /* Expect a server-side error if inserting with the unencrypted collection.
              */
             ret = mongoc_collection_insert_one (
                unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
             if (!ret) {
                printf ("insert with unencrypted collection failed: %s\n", error.message);
                memset (&error, 0, sizeof (error));
             }

             exit_status = EXIT_SUCCESS;
          fail:
             if (error.code) {
                fprintf (stderr, "error: %s\n", error.message);
             }

             bson_free (local_masterkey);
             bson_destroy (kms_providers);
             mongoc_collection_destroy (keyvault_coll);
             mongoc_index_model_destroy (index_model);
             bson_destroy (index_opts);
             bson_destroy (index_keys);
             bson_json_reader_destroy (reader);
             mongoc_auto_encryption_opts_destroy (auto_encryption_opts);
             mongoc_collection_destroy (coll);
             mongoc_client_destroy (client);
             bson_destroy (to_insert);
             mongoc_collection_destroy (unencrypted_coll);
             mongoc_client_destroy (unencrypted_client);
             mongoc_client_destroy (keyvault_client);
             bson_destroy (schema);
             bson_destroy (create_cmd);
             bson_destroy (create_cmd_opts);
             mongoc_write_concern_destroy (wc);

             mongoc_cleanup ();
             return exit_status;
          }

   Explicit Encryption
       Explicit encryption is a MongoDB  community  feature  and  does  not  use  Query  Analysis
       (mongocryptd    or    crypt_shared).    Explicit    encryption    is   provided   by   the
       mongoc_client_encryption_t class, for example:

       client-side-encryption-explicit.c

          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>

          #include "client-side-encryption-helpers.h"

          /* This example demonstrates how to use explicit encryption and decryption using
           * the community version of MongoDB */
          int
          main (void)
          {
          /* The collection used to store the encryption data keys. */
          #define KEYVAULT_DB "encryption"
          #define KEYVAULT_COLL "__libmongocTestKeyVault"
          /* The collection used to store the encrypted documents in this example. */
          #define ENCRYPTED_DB "test"
          #define ENCRYPTED_COLL "coll"

             int exit_status = EXIT_FAILURE;
             bool ret;
             uint8_t *local_masterkey = NULL;
             uint32_t local_masterkey_len;
             bson_t *kms_providers = NULL;
             bson_error_t error = {0};
             bson_t *index_keys = NULL;
             bson_t *index_opts = NULL;
             mongoc_index_model_t *index_model = NULL;
             bson_t *schema = NULL;
             mongoc_client_t *client = NULL;
             mongoc_collection_t *coll = NULL;
             mongoc_collection_t *keyvault_coll = NULL;
             bson_t *to_insert = NULL;
             bson_t *create_cmd = NULL;
             bson_t *create_cmd_opts = NULL;
             mongoc_write_concern_t *wc = NULL;
             mongoc_client_encryption_t *client_encryption = NULL;
             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
             char *keyaltnames[] = {"mongoc_encryption_example_3"};
             bson_value_t datakey_id = {0};
             bson_value_t encrypted_field = {0};
             bson_value_t to_encrypt = {0};
             mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
             bson_value_t decrypted = {0};

             mongoc_init ();

             /* Configure the master key. This must be the same master key that was used
              * to create the encryption key. */
             local_masterkey =
                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
             if (!local_masterkey || local_masterkey_len != 96) {
                fprintf (stderr,
                         "Specify LOCAL_MASTERKEY environment variable as a "
                         "secure random 96 byte hex value.\n");
                goto fail;
             }

             kms_providers = BCON_NEW ("local",
                                       "{",
                                       "key",
                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
                                       "}");

             /* The mongoc_client_t used to read/write application data. */
             client =
                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);

             /* Clear old data */
             mongoc_collection_drop (coll, NULL);

             /* Set up the key vault for this example. */
             keyvault_coll =
                mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
             mongoc_collection_drop (keyvault_coll, NULL);

             /* Create a unique index to ensure that two data keys cannot share the same
              * keyAltName. This is recommended practice for the key vault. */
             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
             index_opts = BCON_NEW ("unique",
                                    BCON_BOOL (true),
                                    "partialFilterExpression",
                                    "{",
                                    "keyAltNames",
                                    "{",
                                    "$exists",
                                    BCON_BOOL (true),
                                    "}",
                                    "}");
             index_model = mongoc_index_model_new (index_keys, index_opts);
             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
                                                               &index_model,
                                                               1,
                                                               NULL /* opts */,
                                                               NULL /* reply */,
                                                               &error);

             if (!ret) {
                goto fail;
             }

             client_encryption_opts = mongoc_client_encryption_opts_new ();
             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
                                                              kms_providers);
             mongoc_client_encryption_opts_set_keyvault_namespace (
                client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);

             /* Set a mongoc_client_t to use for reading/writing to the key vault. This
              * can be the same mongoc_client_t used by the main application. */
             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
                                                                client);
             client_encryption =
                mongoc_client_encryption_new (client_encryption_opts, &error);
             if (!client_encryption) {
                goto fail;
             }

             /* Create a new data key for the encryptedField.
              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
              */
             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
             mongoc_client_encryption_datakey_opts_set_keyaltnames (
                datakey_opts, keyaltnames, 1);
             if (!mongoc_client_encryption_create_datakey (
                    client_encryption, "local", datakey_opts, &datakey_id, &error)) {
                goto fail;
             }

             /* Explicitly encrypt a field */
             encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
             mongoc_client_encryption_encrypt_opts_set_algorithm (
                encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
             mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id);
             to_encrypt.value_type = BSON_TYPE_UTF8;
             to_encrypt.value.v_utf8.str = "123456789";
             const size_t len = strlen (to_encrypt.value.v_utf8.str);
             BSON_ASSERT (bson_in_range_unsigned (uint32_t, len));
             to_encrypt.value.v_utf8.len = (uint32_t) len;

             ret = mongoc_client_encryption_encrypt (
                client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
             if (!ret) {
                goto fail;
             }

             to_insert = bson_new ();
             BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
             ret = mongoc_collection_insert_one (
                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
             if (!ret) {
                goto fail;
             }

             printf ("encrypted document: ");
             if (!print_one_document (coll, &error)) {
                goto fail;
             }
             printf ("\n");

             /* Explicitly decrypt a field */
             ret = mongoc_client_encryption_decrypt (
                client_encryption, &encrypted_field, &decrypted, &error);
             if (!ret) {
                goto fail;
             }
             printf ("decrypted value: %s\n", decrypted.value.v_utf8.str);

             exit_status = EXIT_SUCCESS;
          fail:
             if (error.code) {
                fprintf (stderr, "error: %s\n", error.message);
             }

             bson_free (local_masterkey);
             bson_destroy (kms_providers);
             mongoc_collection_destroy (keyvault_coll);
             mongoc_index_model_destroy (index_model);
             bson_destroy (index_opts);
             bson_destroy (index_keys);
             mongoc_collection_destroy (coll);
             mongoc_client_destroy (client);
             bson_destroy (to_insert);
             bson_destroy (schema);
             bson_destroy (create_cmd);
             bson_destroy (create_cmd_opts);
             mongoc_write_concern_destroy (wc);
             mongoc_client_encryption_destroy (client_encryption);
             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
             mongoc_client_encryption_opts_destroy (client_encryption_opts);
             bson_value_destroy (&encrypted_field);
             mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
             bson_value_destroy (&decrypted);
             bson_value_destroy (&datakey_id);

             mongoc_cleanup ();
             return exit_status;
          }

   Explicit Encryption with Automatic Decryption
       Although automatic encryption requires MongoDB 4.2  enterprise  or  a  MongoDB  4.2  Atlas
       cluster,  automatic  decryption  is  supported  for  all  users.  To  configure  automatic
       decryption   without   automatic    encryption    set    bypass_auto_encryption=True    in
       mongoc_auto_encryption_opts_t:

       client-side-encryption-auto-decryption.c

          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>

          #include "client-side-encryption-helpers.h"

          /* This example demonstrates how to set up automatic decryption without
           * automatic encryption using the community version of MongoDB */
          int
          main (void)
          {
          /* The collection used to store the encryption data keys. */
          #define KEYVAULT_DB "encryption"
          #define KEYVAULT_COLL "__libmongocTestKeyVault"
          /* The collection used to store the encrypted documents in this example. */
          #define ENCRYPTED_DB "test"
          #define ENCRYPTED_COLL "coll"

             int exit_status = EXIT_FAILURE;
             bool ret;
             uint8_t *local_masterkey = NULL;
             uint32_t local_masterkey_len;
             bson_t *kms_providers = NULL;
             bson_error_t error = {0};
             bson_t *index_keys = NULL;
             bson_t *index_opts = NULL;
             mongoc_index_model_t *index_model = NULL;
             bson_t *schema = NULL;
             mongoc_client_t *client = NULL;
             mongoc_collection_t *coll = NULL;
             mongoc_collection_t *keyvault_coll = NULL;
             bson_t *to_insert = NULL;
             bson_t *create_cmd = NULL;
             bson_t *create_cmd_opts = NULL;
             mongoc_write_concern_t *wc = NULL;
             mongoc_client_encryption_t *client_encryption = NULL;
             mongoc_client_encryption_opts_t *client_encryption_opts = NULL;
             mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL;
             char *keyaltnames[] = {"mongoc_encryption_example_4"};
             bson_value_t datakey_id = {0};
             bson_value_t encrypted_field = {0};
             bson_value_t to_encrypt = {0};
             mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL;
             bson_value_t decrypted = {0};
             mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL;
             mongoc_client_t *unencrypted_client = NULL;
             mongoc_collection_t *unencrypted_coll = NULL;

             mongoc_init ();

             /* Configure the master key. This must be the same master key that was used
              * to create the encryption key. */
             local_masterkey =
                hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len);
             if (!local_masterkey || local_masterkey_len != 96) {
                fprintf (stderr,
                         "Specify LOCAL_MASTERKEY environment variable as a "
                         "secure random 96 byte hex value.\n");
                goto fail;
             }

             kms_providers = BCON_NEW ("local",
                                       "{",
                                       "key",
                                       BCON_BIN (0, local_masterkey, local_masterkey_len),
                                       "}");

             client =
                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
             auto_encryption_opts = mongoc_auto_encryption_opts_new ();
             mongoc_auto_encryption_opts_set_keyvault_namespace (
                auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);
             mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts,
                                                            kms_providers);

             /* Setting bypass_auto_encryption to true disables automatic encryption but
              * keeps the automatic decryption behavior. bypass_auto_encryption will also
              * disable spawning mongocryptd */
             mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts,
                                                                     true);

             /* Once bypass_auto_encryption is set, community users can enable auto
              * encryption on the client. This will, in fact, only perform automatic
              * decryption. */
             ret = mongoc_client_enable_auto_encryption (
                client, auto_encryption_opts, &error);
             if (!ret) {
                goto fail;
             }

             /* Now that automatic decryption is on, we can test it by inserting a
              * document with an explicitly encrypted value into the collection. When we
              * look up the document later, it should be automatically decrypted for us.
              */
             coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL);

             /* Clear old data */
             mongoc_collection_drop (coll, NULL);

             /* Set up the key vault for this example. */
             keyvault_coll =
                mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL);
             mongoc_collection_drop (keyvault_coll, NULL);

             /* Create a unique index to ensure that two data keys cannot share the same
              * keyAltName. This is recommended practice for the key vault. */
             index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1));
             index_opts = BCON_NEW ("unique",
                                    BCON_BOOL (true),
                                    "partialFilterExpression",
                                    "{",
                                    "keyAltNames",
                                    "{",
                                    "$exists",
                                    BCON_BOOL (true),
                                    "}",
                                    "}");
             index_model = mongoc_index_model_new (index_keys, index_opts);
             ret = mongoc_collection_create_indexes_with_opts (keyvault_coll,
                                                               &index_model,
                                                               1,
                                                               NULL /* opts */,
                                                               NULL /* reply */,
                                                               &error);

             if (!ret) {
                goto fail;
             }

             client_encryption_opts = mongoc_client_encryption_opts_new ();
             mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts,
                                                              kms_providers);
             mongoc_client_encryption_opts_set_keyvault_namespace (
                client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL);

             /* The key vault client is used for reading to/from the key vault. This can
              * be the same mongoc_client_t used by the application. */
             mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts,
                                                                client);
             client_encryption =
                mongoc_client_encryption_new (client_encryption_opts, &error);
             if (!client_encryption) {
                goto fail;
             }

             /* Create a new data key for the encryptedField.
              * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules
              */
             datakey_opts = mongoc_client_encryption_datakey_opts_new ();
             mongoc_client_encryption_datakey_opts_set_keyaltnames (
                datakey_opts, keyaltnames, 1);
             ret = mongoc_client_encryption_create_datakey (
                client_encryption, "local", datakey_opts, &datakey_id, &error);
             if (!ret) {
                goto fail;
             }

             /* Explicitly encrypt a field. */
             encrypt_opts = mongoc_client_encryption_encrypt_opts_new ();
             mongoc_client_encryption_encrypt_opts_set_algorithm (
                encrypt_opts, MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC);
             mongoc_client_encryption_encrypt_opts_set_keyaltname (
                encrypt_opts, "mongoc_encryption_example_4");
             to_encrypt.value_type = BSON_TYPE_UTF8;
             to_encrypt.value.v_utf8.str = "123456789";
             const size_t len = strlen (to_encrypt.value.v_utf8.str);
             BSON_ASSERT (bson_in_range_unsigned (uint32_t, len));
             to_encrypt.value.v_utf8.len = (uint32_t) len;

             ret = mongoc_client_encryption_encrypt (
                client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error);
             if (!ret) {
                goto fail;
             }

             to_insert = bson_new ();
             BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field);
             ret = mongoc_collection_insert_one (
                coll, to_insert, NULL /* opts */, NULL /* reply */, &error);
             if (!ret) {
                goto fail;
             }

             /* When we retrieve the document, any encrypted fields will get automatically
              * decrypted by the driver. */
             printf ("decrypted document: ");
             if (!print_one_document (coll, &error)) {
                goto fail;
             }
             printf ("\n");

             unencrypted_client =
                mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption");
             unencrypted_coll = mongoc_client_get_collection (
                unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL);

             printf ("encrypted document: ");
             if (!print_one_document (unencrypted_coll, &error)) {
                goto fail;
             }
             printf ("\n");

             exit_status = EXIT_SUCCESS;
          fail:
             if (error.code) {
                fprintf (stderr, "error: %s\n", error.message);
             }

             bson_free (local_masterkey);
             bson_destroy (kms_providers);
             mongoc_collection_destroy (keyvault_coll);
             mongoc_index_model_destroy (index_model);
             bson_destroy (index_opts);
             bson_destroy (index_keys);
             mongoc_collection_destroy (coll);
             mongoc_client_destroy (client);
             bson_destroy (to_insert);
             bson_destroy (schema);
             bson_destroy (create_cmd);
             bson_destroy (create_cmd_opts);
             mongoc_write_concern_destroy (wc);
             mongoc_client_encryption_destroy (client_encryption);
             mongoc_client_encryption_datakey_opts_destroy (datakey_opts);
             mongoc_client_encryption_opts_destroy (client_encryption_opts);
             bson_value_destroy (&encrypted_field);
             mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts);
             bson_value_destroy (&decrypted);
             bson_value_destroy (&datakey_id);
             mongoc_collection_destroy (unencrypted_coll);
             mongoc_client_destroy (unencrypted_client);
             mongoc_auto_encryption_opts_destroy (auto_encryption_opts);

             mongoc_cleanup ();
             return exit_status;
          }

   Queryable Encryption
       Using Queryable Encryption requires MongoDB Server 7.0 or higher.

       See the MongoDB Manual for Queryable Encryption for more information about the feature.

       API  related to the "rangePreview" algorithm is still experimental and subject to breaking
       changes!

   Queryable Encryption in older MongoDB Server versions
       MongoDB Server 6.0 introduced Queryable Encryption as a Public Technical Preview.  MongoDB
       Server 7.0 includes backwards breaking changes to the Queryable Encryption protocol.

       The  backwards breaking changes are applied in the client protocol in libmongocrypt 1.8.0.
       libmongoc 1.24.0 requires libmongocrypt  1.8.0  or  newer.   libmongoc  1.24.0  no  longer
       supports  Queryable  Encryption  in  MongoDB  Server  <7.0.   Using  Queryable  Encryption
       libmongoc 1.24.0 and higher requires MongoDB Server >=7.0.

       Using Queryable Encryption with libmongocrypt<1.8.0 on a  MongoDB  Server>=7.0,  or  using
       libmongocrypt>=1.8.0  on a MongoDB Server<6.0 will result in a server error when using the
       incompatible protocol.

       SEE ALSO:
          The MongoDB Manual for Queryable Encryption

   Installation
       Using In-Use Encryption in the C driver requires the  dependency  libmongocrypt.  See  the
       MongoDB Manual for libmongocrypt installation instructions.

       Once     libmongocrypt     is     installed,     configure     the     C    driver    with
       -DENABLE_CLIENT_SIDE_ENCRYPTION=ON to require In-Use Encryption be enabled.

          $ cd mongo-c-driver
          $ mkdir cmake-build && cd cmake-build
          $ cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_CLIENT_SIDE_ENCRYPTION=ON ..
          $ cmake --build . --target install

   API
       mongoc_client_encryption_t  is  used  for  explicit   encryption   and   key   management.
       mongoc_client_enable_auto_encryption()  and mongoc_client_pool_enable_auto_encryption() is
       used to enable automatic encryption.

       The Queryable Encryption and  CSFLE  features  share  much  of  the  same  API  with  some
       exceptions.

       • The              supported              algorithms             documented             in
         mongoc_client_encryption_encrypt_opts_set_algorithm() do not apply to both features.

       • mongoc_auto_encryption_opts_set_encrypted_fields_map()   only   applies   to   Queryable
         Encryption.

       • mongoc_auto_encryption_opts_set_schema_map() only applies to CSFLE.

   Query Analysis
       To  support  the  automatic  encryption  feature,  one  of  the following dependencies are
       required:

       • The mongocryptd executable. See the MongoDB Manual documentation: Install and  Configure
         mongocryptd

       • The  crypt_shared  library.  See  the MongoDB Manual documentation: Automatic Encryption
         Shared Library

       A  mongoc_client_t  or  mongoc_client_pool_t  configured   with   auto   encryption   will
       automatically  try  to  load the crypt_shared library. If loading the crypt_shared library
       fails, the mongoc_client_t or mongoc_client_pool_t  will  try  to  spawn  the  mongocryptd
       process  from the application's PATH. To configure use of crypt_shared and mongocryptd see
       mongoc_auto_encryption_opts_set_extra().

   API Reference
   Initialization and cleanup
   Synopsis
       Initialize the MongoDB C Driver by calling mongoc_init() exactly once at the beginning  of
       your  program.  It  is responsible for initializing global state such as process counters,
       SSL, and threading primitives.

       Exception to this is mongoc_log_set_handler(), which should be called before mongoc_init()
       or some log traces would not use your log handling function. See Custom Log Handlers for a
       detailed example.

       Call mongoc_cleanup() exactly once at the end of your program to release  all  memory  and
       other  resources  allocated  by  the  driver. You must not call any other MongoDB C Driver
       functions after mongoc_cleanup(). Note that mongoc_init() does not reinitialize the driver
       after mongoc_cleanup().

   Deprecated feature: automatic initialization and cleanup
       On  some  platforms  the driver can automatically call mongoc_init() before main, and call
       mongoc_cleanup() as the process exits. This is problematic  in  situations  where  related
       libraries  also execute cleanup code on shutdown, and it creates inconsistent rules across
       platforms. Therefore the automatic initialization and cleanup feature is  deprecated,  and
       will  be  dropped  in  version  2.0. Meanwhile, for backward compatibility, the feature is
       enabled by default on platforms where it is available.

       For portable, future-proof code, always call mongoc_init() and mongoc_cleanup()  yourself,
       and configure the driver like:

          cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF

   Logging
       MongoDB C driver Logging Abstraction

   Synopsis
          typedef enum {
             MONGOC_LOG_LEVEL_ERROR,
             MONGOC_LOG_LEVEL_CRITICAL,
             MONGOC_LOG_LEVEL_WARNING,
             MONGOC_LOG_LEVEL_MESSAGE,
             MONGOC_LOG_LEVEL_INFO,
             MONGOC_LOG_LEVEL_DEBUG,
             MONGOC_LOG_LEVEL_TRACE,
          } mongoc_log_level_t;

          #define MONGOC_ERROR(...)
          #define MONGOC_CRITICAL(...)
          #define MONGOC_WARNING(...)
          #define MONGOC_MESSAGE(...)
          #define MONGOC_INFO(...)
          #define MONGOC_DEBUG(...)

          typedef void (*mongoc_log_func_t) (mongoc_log_level_t log_level,
                                             const char *log_domain,
                                             const char *message,
                                             void *user_data);

          void
          mongoc_log_set_handler (mongoc_log_func_t log_func, void *user_data);
          void
          mongoc_log (mongoc_log_level_t log_level,
                      const char *log_domain,
                      const char *format,
                      ...) BSON_GNUC_PRINTF (3, 4);
          const char *
          mongoc_log_level_str (mongoc_log_level_t log_level);
          void
          mongoc_log_default_handler (mongoc_log_level_t log_level,
                                      const char *log_domain,
                                      const char *message,
                                      void *user_data);
          void
          mongoc_log_trace_enable (void);
          void
          mongoc_log_trace_disable (void);

       The  MongoDB  C  driver  comes  with  an  abstraction for logging that you can use in your
       application, or integrate with an existing logging system.

   Macros
       To make logging a little less  painful,  various  helper  macros  are  provided.  See  the
       following example.

          #undef MONGOC_LOG_DOMAIN
          #define MONGOC_LOG_DOMAIN "my-custom-domain"

          MONGOC_WARNING ("An error occurred: %s", strerror (errno));

   Custom Log Handlers
       The default log handler prints a timestamp and the log message to stdout, or to stderr for
       warnings, critical messages, and errors.
              You can override the handler with mongoc_log_set_handler().  Your handler  function
              is called in a mutex for thread safety.

       For  example,  you  could register a custom handler to suppress messages at INFO level and
       below:

          void
          my_logger (mongoc_log_level_t log_level,
                     const char *log_domain,
                     const char *message,
                     void *user_data)
          {
             /* smaller values are more important */
             if (log_level < MONGOC_LOG_LEVEL_INFO) {
                mongoc_log_default_handler (log_level, log_domain, message, user_data);
             }
          }

          int
          main (int argc, char *argv[])
          {
             mongoc_log_set_handler (my_logger, NULL);
             mongoc_init ();

             /* ... your code ...  */

             mongoc_cleanup ();
             return 0;
          }

       Note that in the example above mongoc_log_set_handler() is  called  before  mongoc_init().
       Otherwise, some log traces could not be processed by the log handler.

       To restore the default handler:

          mongoc_log_set_handler (mongoc_log_default_handler, NULL);

   Disable logging
       To disable all logging, including warnings, critical messages and errors, provide an empty
       log handler:

          mongoc_log_set_handler (NULL, NULL);

   Tracing
       If  compiling  your  own  copy  of  the  MongoDB  C  driver,  consider  configuring   with
       -DENABLE_TRACING=ON  to enable function tracing and hex dumps of network packets to STDERR
       and STDOUT during development and debugging.

       This is especially useful when debugging what may be going on internally in the driver.

       Trace messages can be  enabled  and  disabled  by  calling  mongoc_log_trace_enable()  and
       mongoc_log_trace_disable()

       NOTE:
          Compiling  the  driver  with -DENABLE_TRACING=ON will affect its performance. Disabling
          tracing with mongoc_log_trace_disable() significantly reduces the overhead, but  cannot
          remove it completely.
       « libmongoc

   Error Reporting
   Description
       Many  C  Driver  functions  report  errors  by  returning  false  or  -1 and filling out a
       bson_error_t structure with an error domain,  error  code,  and  message.  Use  domain  to
       determine which subsystem generated the error, and code for the specific error. message is
       a human-readable error description.

       SEE ALSO:
          Handling Errors in libbson.

┌────────────────────────────────────┬──────────────────────────────────────────────┬────────────────────────────────────────────┐
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_CLIENTMONGOC_ERROR_CLIENT_TOO_BIG                  │ You   tried  to  send  a                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_CLIENT_AUTHENTICATE             │ Wrong   credentials,  or                   │
└────────────────────────────────────┴──────────────────────────────────────────────┴────────────────────────────────────────────┘

│                                    │ MONGOC_ERROR_CLIENT_NO_ACCEPTABLE_PEER       │ You    tried    an   TLS                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_CLIENT_IN_EXHAUST               │ You began  iterating  an                   │
│                                    │                                              │ mongoc_client_t.                           │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_CLIENT_SESSION_FAILURE          │ Failure    related    to                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG   │ Failure    related    to                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE │ Failure    related    to                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_CLIENT_INVALID_LOAD_BALANCER    │ You attempted to connect                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_STREAMMONGOC_ERROR_STREAM_NAME_RESOLUTION          │ DNS failure.                               │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_STREAM_SOCKET                   │ Timeout    communicating                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_STREAM_CONNECT                  │ Failed   to  connect  to                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_PROTOCOLMONGOC_ERROR_PROTOCOL_INVALID_REPLY          │ Corrupt  response   from                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION       │ The  server  version  is                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_CURSORMONGOC_ERROR_CURSOR_INVALID_CURSOR           │ You passed bad arguments                   │
│                                    │                                              │ mongoc_collection_find_with_opts(),        │
│                                    │                                              │ mongoc_cursor_next()  on                   │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_CHANGE_STREAM_NO_RESUME_TOKEN   │ A  resume token was not returned in        │
│                                    │                                              │ mongoc_change_stream_next()                │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_QUERYMONGOC_ERROR_QUERY_FAILUREError  API  Version 1: Server error        │
│                                    │                                              │ error message is in message.               │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_SERVERMONGOC_ERROR_QUERY_FAILUREError  API  Version 2: Server error        │
│                                    │                                              │ error message is in message.               │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_SASL                   │ A SASL error code.                           │ man   sasl_errors  for  a  list  of        │
└────────────────────────────────────┴──────────────────────────────────────────────┴────────────────────────────────────────────┘

│MONGOC_ERROR_BSONMONGOC_ERROR_BSON_INVALID                    │ You passed an invalid or  oversized        │
│                                    │                                              │ mongoc_collection_create_index()           │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_NAMESPACEMONGOC_ERROR_NAMESPACE_INVALID               │ You  tried  to  create a collection        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_COMMANDMONGOC_ERROR_COMMAND_INVALID_ARG             │ Many functions set this error  code        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION       │ You tried to use a  command  option        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_DUPLICATE_KEY                   │ An  insert or update failed because        │
│                                    │                                              │ because of a duplicate _id or other        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_MAX_TIME_MS_EXPIRED             │ The    operation   failed   because        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_SERVER_SELECTION_INVALID_ID     │ The   serverId   option   for    an        │
│                                    │                                              │ session  (denoted  by the sessionId        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_COMMANDError code from server.                      │ Error API Version 1:  Server  error        │
│                                    │                                              │ message is in message.                     │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_SERVERError code from server.                      │ Error API Version 2:  Server  error        │
│                                    │                                              │ message is in message.                     │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_COLLECTIONMONGOC_ERROR_COLLECTION_INSERT_FAILED,       │ Invalid   or   empty    input    to        │
│                                    │ MONGOC_ERROR_COLLECTION_UPDATE_FAILED,       │ mongoc_collection_insert_one(),            │
│                                    │ MONGOC_ERROR_COLLECTION_DELETE_FAILED.       │ mongoc_collection_insert_bulk(),           │
│                                    │                                              │ mongoc_collection_update_one(),            │
│                                    │                                              │ mongoc_collection_update_many(),           │
│                                    │                                              │ mongoc_collection_replace_one(),           │
│                                    │                                              │ mongoc_collection_delete_one(),  or        │
│                                    │                                              │ mongoc_collection_delete_many().           │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_COLLECTIONError code from server.                      │ Error  API  Version 1: Server error        │
│                                    │                                              │ mongoc_collection_insert_one(),            │
│                                    │                                              │ mongoc_collection_insert_bulk(),           │
│                                    │                                              │ mongoc_collection_update_one(),            │
│                                    │                                              │ mongoc_collection_update_many(),           │
│                                    │                                              │ mongoc_collection_replace_one(),           │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_SERVERError code from server.                      │ Error  API  Version 2: Server error        │
│                                    │                                              │ mongoc_collection_insert_one(),            │
│                                    │                                              │ mongoc_collection_insert_bulk(),           │
│                                    │                                              │ mongoc_collection_update_one(),            │
│                                    │                                              │ mongoc_collection_update_many(),           │
│                                    │                                              │ mongoc_collection_replace_one(),           │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_GRIDFSMONGOC_ERROR_GRIDFS_CHUNK_MISSING            │ The   GridFS   file  is  missing  a        │
│                                    │                                              │ document in its chunks collection.         │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_GRIDFS_CORRUPT                  │ A data inconsistency  was  detected        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_GRIDFS_INVALID_FILENAME         │ You   passed  a  NULL  filename  to        │
│                                    │                                              │ mongoc_gridfs_remove_by_filename().        │
└────────────────────────────────────┴──────────────────────────────────────────────┴────────────────────────────────────────────┘

│                                    │ MONGOC_ERROR_GRIDFS_PROTOCOL_ERROR           │ You                          called        │
│                                    │                                              │ mongoc_gridfs_file_set_id()   after        │
│                                    │                                              │ mongoc_gridfs_file_save(), or tried        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_GRIDFS_BUCKET_FILE_NOT_FOUND    │ A GridFS file is missing from files        │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_GRIDFS_BUCKET_STREAM            │ An  error  occurred  on  a   stream        │
│                                    │                                              │ mongoc_gridfs_bucket_upload_from_stream(). │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_SCRAMMONGOC_ERROR_SCRAM_PROTOCOL_ERROR            │ Failure in  SCRAM-SHA-1  or  SCRAM-SHA-256 │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_SERVER_SELECTIONMONGOC_ERROR_SERVER_SELECTION_FAILURE        │ No  replica  set  member  or   mongos   is │
│                                    │                                              │ available,   or  none  matches  your  read │
│                                    │                                              │ preference, or  you  supplied  an  invalid │
│                                    │                                              │ mongoc_read_prefs_t.                       │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_WRITE_CONCERNError code from server.                      │ There was a write concern error or timeout │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_TRANSACTIONMONGOC_ERROR_TRANSACTION_INVALID             │ You attempted to start a transaction  when │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION │ Error code produced by libmongocrypt.        │ An   error   occurred   in   the   library │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_AZUREMONGOC_ERROR_KMS_SERVER_HTTP                 │ An Azure HTTP service  responded  with  an │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_KMS_SERVER_BAD_JSON             │ An  Azure  service  responded with invalid │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│MONGOC_ERROR_GCPMONGOC_ERROR_KMS_SERVER_HTTP                 │ A GCP HTTP service responded with an error │
├────────────────────────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────┤
│                                    │ MONGOC_ERROR_KMS_SERVER_BAD_JSON             │ A  GCP service responded with invalid JSON │
└────────────────────────────────────┴──────────────────────────────────────────────┴────────────────────────────────────────────┘

   Error Labels
       In some cases your application must make decisions based on what  category  of  error  the
       driver  has  returned, but these categories do not correspond perfectly to an error domain
       or code. In such cases, error  labels  provide  a  reliable  way  to  determine  how  your
       application should respond to an error.

       Any C Driver function that has a bson_t out-parameter named reply may include error labels
       to the reply, in the form of a BSON field  named  "errorLabels"  containing  an  array  of
       strings:

          { "errorLabels": [ "TransientTransactionError" ] }

       Use   mongoc_error_has_label()  to  test  if  a  reply  contains  a  specific  label.  See
       mongoc_client_session_start_transaction() for example code that demonstrates  the  use  of
       error labels in application logic.

       The following error labels are currently defined. Future versions of MongoDB may introduce
       new labels.

   TransientTransactionError
       Within a multi-document transaction, certain  errors  can  leave  the  transaction  in  an
       unknown  or  aborted  state. These include write conflicts, primary stepdowns, and network
       errors. In response, the application  should  abort  the  transaction  and  try  the  same
       sequence of operations again in a new transaction.

   UnknownTransactionCommitResult
       When  mongoc_client_session_commit_transaction()  encounters  a  network  error or certain
       server errors, it is not known whether the transaction was committed. Applications  should
       attempt  to commit the transaction again until: the commit succeeds, the commit fails with
       an error not labeled "UnknownTransactionCommitResult", or the application chooses to  give
       up.

   Setting the Error API Version
       The  driver's  error  reporting  began  with  a  design  flaw:  when  the  error domain is
       MONGOC_ERROR_COLLECTION, MONGOC_ERROR_QUERY, or MONGOC_ERROR_COMMAND, the error code might
       originate  from the server or the driver. An application cannot always know where an error
       originated, and therefore cannot tell what the code means.

       For   example,   if   mongoc_collection_update_one()   sets   the   error's   domain    to
       MONGOC_ERROR_COLLECTION  and its code to 24, the application cannot know whether 24 is the
       generic driver error code MONGOC_ERROR_COLLECTION_UPDATE_FAILED  or  the  specific  server
       error code "LockTimeout".

       To  fix  this  flaw  while  preserving backward compatibility, the C Driver 1.4 introduces
       "Error API Versions". Version 1, the default  Error  API  Version,  maintains  the  flawed
       behavior.  Version  2  adds  a  new error domain, MONGOC_ERROR_SERVER. In Version 2, error
       codes  originating  on  the  server  always  have  error  domain  MONGOC_ERROR_SERVER   or
       MONGOC_ERROR_WRITE_CONCERN.  When  the  driver  uses  Version 2 the application can always
       determine the origin and meaning of error codes. New applications should  use  Version  2,
       and existing applications should be updated to use Version 2 as well.

┌──────────────────────────────────────────────┬────────────────────────────┬────────────────────────────┐
├──────────────────────────────────────────────┼────────────────────────────┼────────────────────────────┤
│mongoc_cursor_error()MONGOC_ERROR_QUERYMONGOC_ERROR_SERVER        │
├──────────────────────────────────────────────┼────────────────────────────┼────────────────────────────┤
│mongoc_client_command_with_opts(),            │ MONGOC_ERROR_QUERYMONGOC_ERROR_SERVER        │
│mongoc_database_command_with_opts(),          │                            │                            │
├──────────────────────────────────────────────┼────────────────────────────┼────────────────────────────┤
│mongoc_collection_count_with_opts()MONGOC_ERROR_QUERYMONGOC_ERROR_SERVER        │
│mongoc_client_get_database_names_with_opts(), │                            │                            │
├──────────────────────────────────────────────┼────────────────────────────┼────────────────────────────┤
│mongoc_collection_insert_one()MONGOC_ERROR_COMMANDMONGOC_ERROR_SERVER        │
│mongoc_collection_insert_bulk()               │                            │                            │
│mongoc_collection_update_one()                │                            │                            │
│mongoc_collection_update_many()               │                            │                            │
│mongoc_collection_replace_one()               │                            │                            │
│mongoc_collection_delete_one()                │                            │                            │
│mongoc_collection_delete_many()               │                            │                            │
├──────────────────────────────────────────────┼────────────────────────────┼────────────────────────────┤
│mongoc_bulk_operation_execute()MONGOC_ERROR_COMMANDMONGOC_ERROR_SERVER        │
├──────────────────────────────────────────────┼────────────────────────────┼────────────────────────────┤
│Write-concern timeout                         │ MONGOC_ERROR_WRITE_CONCERNMONGOC_ERROR_WRITE_CONCERN │
└──────────────────────────────────────────────┴────────────────────────────┴────────────────────────────┘

       The  Error   API   Versions   are   defined   with   MONGOC_ERROR_API_VERSION_LEGACY   and
       MONGOC_ERROR_API_VERSION_2.   Set   the   version  with  mongoc_client_set_error_api()  or
       mongoc_client_pool_set_error_api().

       SEE ALSO:
          MongoDB Server Error Codes

   Object Lifecycle
       This page documents the order of creation and  destruction  for  libmongoc's  main  struct
       types.

   Clients and pools
       Call   mongoc_init()  once,  before  calling  any  other  libmongoc  functions,  and  call
       mongoc_cleanup() once before your program exits.

       A program that uses libmongoc from multiple threads should create  a  mongoc_client_pool_t
       with  mongoc_client_pool_new().  Each thread acquires a mongoc_client_t from the pool with
       mongoc_client_pool_pop() and returns it with mongoc_client_pool_push() when the thread  is
       finished   using   it.   To  destroy  the  pool,  first  return  all  clients,  then  call
       mongoc_client_pool_destroy().

       If your program uses libmongoc from only one thread,  create  a  mongoc_client_t  directly
       with    mongoc_client_new()    or    mongoc_client_new_from_uri().    Destroy    it   with
       mongoc_client_destroy().

   Databases, collections, and related objects
       You can create a mongoc_database_t or  mongoc_collection_t  from  a  mongoc_client_t,  and
       create a mongoc_cursor_t or mongoc_bulk_operation_t from a mongoc_collection_t.

       Each  of  these  objects  must  be destroyed before the client they were created from, but
       their lifetimes are otherwise independent.

   GridFS objects
       You can create a mongoc_gridfs_t from a mongoc_client_t, create a mongoc_gridfs_file_t  or
       mongoc_gridfs_file_list_t  from  a  mongoc_gridfs_t,  create a mongoc_gridfs_file_t from a
       mongoc_gridfs_file_list_t, and create a mongoc_stream_t from a mongoc_gridfs_file_t.

       Each of these objects depends on the object it was created  from.  Always  destroy  GridFS
       objects  in  the  reverse  of  the  order  they were created. The sole exception is that a
       mongoc_gridfs_file_t need not be destroyed before  the  mongoc_gridfs_file_list_t  it  was
       created from.

   GridFS bucket objects
       Create mongoc_gridfs_bucket_t with a mongoc_database_t derived from a mongoc_client_t. The
       mongoc_database_t is independent from the mongoc_gridfs_bucket_t. But the  mongoc_client_t
       must outlive the mongoc_gridfs_bucket_t.

       A    mongoc_stream_t    may    be    created    from   the   mongoc_gridfs_bucket_t.   The
       mongoc_gridfs_bucket_t must outlive the mongoc_stream_t.

   Sessions
       Start a session with mongoc_client_start_session(), use the  session  for  a  sequence  of
       operations      and     multi-document     transactions,     then     free     it     with
       mongoc_client_session_destroy(). Any mongoc_cursor_t  or  mongoc_change_stream_t  using  a
       session  must  be destroyed before the session, and a session must be destroyed before the
       mongoc_client_t it came from.

       By default, sessions are  causally  consistent.  To  disable  causal  consistency,  before
       starting  a  session create a mongoc_session_opt_t with mongoc_session_opts_new() and call
       mongoc_session_opts_set_causal_consistency(),    then     free     the     struct     with
       mongoc_session_opts_destroy().

       Unacknowledged writes are prohibited with sessions.

       A  mongoc_client_session_t  must  be  used  by  only  one thread at a time. Due to session
       pooling, mongoc_client_start_session() may return a session that has been  idle  for  some
       time  and  is about to be closed after its idle timeout. Use the session within one minute
       of acquiring it to refresh the session and avoid a timeout.

   Client Side Encryption
       When    configuring     a     mongoc_client_t     for     automatic     encryption     via
       mongoc_client_enable_auto_encryption(),  if  a  separate  key  vault  client is set in the
       options (via mongoc_auto_encryption_opts_set_keyvault_client()) the key vault client  must
       outlive the encrypted client.

       When     configuring    a    mongoc_client_pool_t    for    automatic    encryption    via
       mongoc_client_pool_enable_auto_encryption(), if a separate key vault client pool is set in
       the  options  (via  mongoc_auto_encryption_opts_set_keyvault_client_pool())  the key vault
       client pool must outlive the encrypted client pool.

       When creating a mongoc_client_encryption_t, the  configured  key  vault  client  (set  via
       mongoc_client_encryption_opts_set_keyvault_client())        must        outlive        the
       mongoc_client_encryption_t.

   GridFS
       The C driver includes two APIs for GridFS.

       The older API consists of mongoc_gridfs_t and its derivatives. It contains deprecated API,
       does not support read preferences, and is not recommended in new applications. It does not
       conform to the MongoDB GridFS specification.

       The newer API consists of mongoc_gridfs_bucket_t and allows uploading/downloading  through
       derived mongoc_stream_t objects. It conforms to the MongoDB GridFS specification.

       There  is  not  always  a  straightforward  upgrade  path  from  an application built with
       mongoc_gridfs_t to mongoc_gridfs_bucket_t (e.g. a mongoc_gridfs_file_t provides  functions
       to seek but mongoc_stream_t does not). But users are encouraged to upgrade when possible.

   mongoc_auto_encryption_opts_t
       Options for enabling automatic encryption and decryption for In-Use Encryption.

   Synopsis
          typedef struct _mongoc_auto_encryption_opts_t mongoc_auto_encryption_opts_t;

       SEE ALSO:
          In-Use Encryption

   mongoc_bulk_operation_t
       Bulk Write Operations

   Synopsis
          typedef struct _mongoc_bulk_operation_t mongoc_bulk_operation_t;

       The  opaque  type  mongoc_bulk_operation_t provides an abstraction for submitting multiple
       write operations as a single batch.

       After  adding  all  of  the  write  operations  to   the   mongoc_bulk_operation_t,   call
       mongoc_bulk_operation_execute() to execute the operation.

       WARNING:
          It    is    only    valid    to    call   mongoc_bulk_operation_execute()   once.   The
          mongoc_bulk_operation_t must be destroyed afterwards.

       SEE ALSO:
          Bulk Write Operations

   mongoc_change_stream_t
   Synopsis
          #include <mongoc/mongoc.h>

          typedef struct _mongoc_change_stream_t mongoc_change_stream_t;

       mongoc_change_stream_t is a handle to a change stream. A collection change stream  can  be
       obtained using mongoc_collection_watch().

       It  is  recommended  to  use  a  mongoc_change_stream_t and its functions instead of a raw
       aggregation with a $changeStream stage. For more information see the MongoDB Manual  Entry
       on Change Streams.

   Example
       example-collection-watch.c

          #include <mongoc/mongoc.h>

          int
          main (void)
          {
             bson_t empty = BSON_INITIALIZER;
             const bson_t *doc;
             bson_t *to_insert = BCON_NEW ("x", BCON_INT32 (1));
             const bson_t *err_doc;
             bson_error_t error;
             const char *uri_string;
             mongoc_uri_t *uri;
             mongoc_client_t *client;
             mongoc_collection_t *coll;
             mongoc_change_stream_t *stream;
             mongoc_write_concern_t *wc = mongoc_write_concern_new ();
             bson_t opts = BSON_INITIALIZER;
             bool r;

             mongoc_init ();

             uri_string = "mongodb://"
                          "localhost:27017,localhost:27018,localhost:"
                          "27019/db?replicaSet=rs0";

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             coll = mongoc_client_get_collection (client, "db", "coll");
             stream = mongoc_collection_watch (coll, &empty, NULL);

             mongoc_write_concern_set_wmajority (wc, 10000);
             mongoc_write_concern_append (wc, &opts);
             r = mongoc_collection_insert_one (coll, to_insert, &opts, NULL, &error);
             if (!r) {
                fprintf (stderr, "Error: %s\n", error.message);
                return EXIT_FAILURE;
             }

             while (mongoc_change_stream_next (stream, &doc)) {
                char *as_json = bson_as_relaxed_extended_json (doc, NULL);
                fprintf (stderr, "Got document: %s\n", as_json);
                bson_free (as_json);
             }

             if (mongoc_change_stream_error_document (stream, &error, &err_doc)) {
                if (!bson_empty (err_doc)) {
                   fprintf (stderr,
                            "Server Error: %s\n",
                            bson_as_relaxed_extended_json (err_doc, NULL));
                } else {
                   fprintf (stderr, "Client Error: %s\n", error.message);
                }
                return EXIT_FAILURE;
             }

             bson_destroy (to_insert);
             mongoc_write_concern_destroy (wc);
             bson_destroy (&opts);
             mongoc_change_stream_destroy (stream);
             mongoc_collection_destroy (coll);
             mongoc_uri_destroy (uri);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

   Starting and Resuming
       All  watch functions accept several options to indicate where a change stream should start
       returning changes from: resumeAfter, startAfter, and startAtOperationTime.

       All changes returned by mongoc_change_stream_next() include a  resume  token  in  the  _id
       field.  MongoDB  4.2  also  includes  an  additional  resume token in each "aggregate" and
       "getMore" command response, which points to the end of that response's batch. The  current
       token  is  automatically cached by libmongoc. In the event of an error, libmongoc attempts
       to recreate the change stream starting where it left off  by  passing  the  cached  resume
       token.  libmongoc  only  attempts  to  resume once, but client applications can access the
       cached resume token with mongoc_change_stream_get_resume_token() and use it for their  own
       resume logic by passing it as either the resumeAfter or startAfter option.

       Additionally, change streams can start returning changes at an operation time by using the
       startAtOperationTime field. This can be the timestamp returned in the operationTime  field
       of a command reply.

       resumeAfter,  startAfter, and startAtOperationTime are mutually exclusive options. Setting
       more than one will result in a server error.

       The following example implements custom resuming logic, persisting the resume token  in  a
       file.

       example-resume.c

          #include <mongoc/mongoc.h>

          /* An example implementation of custom resume logic in a change stream.
          * example-resume starts a client-wide change stream and persists the resume
          * token in a file "resume-token.json". On restart, if "resume-token.json"
          * exists, the change stream starts watching after the persisted resume token.
          *
          * This behavior allows a user to exit example-resume, and restart it later
          * without missing any change events.
          */
          #include <unistd.h>

          static const char *RESUME_TOKEN_PATH = "resume-token.json";

          static bool
          _save_resume_token (const bson_t *doc)
          {
             FILE *file_stream;
             bson_iter_t iter;
             bson_t resume_token_doc;
             char *as_json = NULL;
             size_t as_json_len;
             ssize_t r, n_written;
             const bson_value_t *resume_token;

             if (!bson_iter_init_find (&iter, doc, "_id")) {
                fprintf (stderr, "reply does not contain operationTime.");
                return false;
             }
             resume_token = bson_iter_value (&iter);
             /* store the resume token in a document, { resumeAfter: <resume token> }
              * which we can later append easily. */
             file_stream = fopen (RESUME_TOKEN_PATH, "w+");
             if (!file_stream) {
                fprintf (stderr, "failed to open %s for writing\n", RESUME_TOKEN_PATH);
                return false;
             }
             bson_init (&resume_token_doc);
             BSON_APPEND_VALUE (&resume_token_doc, "resumeAfter", resume_token);
             as_json = bson_as_canonical_extended_json (&resume_token_doc, &as_json_len);
             bson_destroy (&resume_token_doc);
             n_written = 0;
             while (n_written < as_json_len) {
                r = fwrite ((void *) (as_json + n_written),
                            sizeof (char),
                            as_json_len - n_written,
                            file_stream);
                if (r == -1) {
                   fprintf (stderr, "failed to write to %s\n", RESUME_TOKEN_PATH);
                   bson_free (as_json);
                   fclose (file_stream);
                   return false;
                }
                n_written += r;
             }

             bson_free (as_json);
             fclose (file_stream);
             return true;
          }

          bool
          _load_resume_token (bson_t *opts)
          {
             bson_error_t error;
             bson_json_reader_t *reader;
             bson_t doc;

             /* if the file does not exist, skip. */
             if (-1 == access (RESUME_TOKEN_PATH, R_OK)) {
                return true;
             }
             reader = bson_json_reader_new_from_file (RESUME_TOKEN_PATH, &error);
             if (!reader) {
                fprintf (stderr,
                         "failed to open %s for reading: %s\n",
                         RESUME_TOKEN_PATH,
                         error.message);
                return false;
             }

             bson_init (&doc);
             if (-1 == bson_json_reader_read (reader, &doc, &error)) {
                fprintf (stderr, "failed to read doc from %s\n", RESUME_TOKEN_PATH);
                bson_destroy (&doc);
                bson_json_reader_destroy (reader);
                return false;
             }

             printf ("found cached resume token in %s, resuming change stream.\n",
                     RESUME_TOKEN_PATH);

             bson_concat (opts, &doc);
             bson_destroy (&doc);
             bson_json_reader_destroy (reader);
             return true;
          }

          int
          main (void)
          {
             int exit_code = EXIT_FAILURE;
             const char *uri_string;
             mongoc_uri_t *uri = NULL;
             bson_error_t error;
             mongoc_client_t *client = NULL;
             bson_t pipeline = BSON_INITIALIZER;
             bson_t opts = BSON_INITIALIZER;
             mongoc_change_stream_t *stream = NULL;
             const bson_t *doc;

             const int max_time = 30; /* max amount of time, in seconds, that
                                         mongoc_change_stream_next can block. */

             mongoc_init ();
             uri_string = "mongodb://localhost:27017/db?replicaSet=rs0";
             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                goto cleanup;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                goto cleanup;
             }

             if (!_load_resume_token (&opts)) {
                goto cleanup;
             }
             BSON_APPEND_INT64 (&opts, "maxAwaitTimeMS", max_time * 1000);

             printf ("listening for changes on the client (max %d seconds).\n", max_time);
             stream = mongoc_client_watch (client, &pipeline, &opts);

             while (mongoc_change_stream_next (stream, &doc)) {
                char *as_json;

                as_json = bson_as_canonical_extended_json (doc, NULL);
                printf ("change received: %s\n", as_json);
                bson_free (as_json);
                if (!_save_resume_token (doc)) {
                   goto cleanup;
                }
             }

             exit_code = EXIT_SUCCESS;

          cleanup:
             mongoc_uri_destroy (uri);
             bson_destroy (&pipeline);
             bson_destroy (&opts);
             mongoc_change_stream_destroy (stream);
             mongoc_client_destroy (client);
             mongoc_cleanup ();
             return exit_code;
          }

       The following example shows using startAtOperationTime to synchronize a change stream with
       another operation.

       example-start-at-optime.c

          /* An example of starting a change stream with startAtOperationTime. */
          #include <mongoc/mongoc.h>

          int
          main (void)
          {
             int exit_code = EXIT_FAILURE;
             const char *uri_string;
             mongoc_uri_t *uri = NULL;
             bson_error_t error;
             mongoc_client_t *client = NULL;
             mongoc_collection_t *coll = NULL;
             bson_t pipeline = BSON_INITIALIZER;
             bson_t opts = BSON_INITIALIZER;
             mongoc_change_stream_t *stream = NULL;
             bson_iter_t iter;
             const bson_t *doc;
             bson_value_t cached_operation_time = {0};
             int i;
             bool r;

             mongoc_init ();
             uri_string = "mongodb://localhost:27017/db?replicaSet=rs0";
             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                goto cleanup;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                goto cleanup;
             }

             /* insert five documents. */
             coll = mongoc_client_get_collection (client, "db", "coll");
             for (i = 0; i < 5; i++) {
                bson_t reply;
                bson_t *insert_cmd = BCON_NEW ("insert",
                                               "coll",
                                               "documents",
                                               "[",
                                               "{",
                                               "x",
                                               BCON_INT64 (i),
                                               "}",
                                               "]");

                r = mongoc_collection_write_command_with_opts (
                   coll, insert_cmd, NULL, &reply, &error);
                bson_destroy (insert_cmd);
                if (!r) {
                   bson_destroy (&reply);
                   fprintf (stderr, "failed to insert: %s\n", error.message);
                   goto cleanup;
                }
                if (i == 0) {
                   /* cache the operation time in the first reply. */
                   if (bson_iter_init_find (&iter, &reply, "operationTime")) {
                      bson_value_copy (bson_iter_value (&iter), &cached_operation_time);
                   } else {
                      fprintf (stderr, "reply does not contain operationTime.");
                      bson_destroy (&reply);
                      goto cleanup;
                   }
                }
                bson_destroy (&reply);
             }

             /* start a change stream at the first returned operationTime. */
             BSON_APPEND_VALUE (&opts, "startAtOperationTime", &cached_operation_time);
             stream = mongoc_collection_watch (coll, &pipeline, &opts);

             /* since the change stream started at the operation time of the first
              * insert, the five inserts are returned. */
             printf ("listening for changes on db.coll:\n");
             while (mongoc_change_stream_next (stream, &doc)) {
                char *as_json;

                as_json = bson_as_canonical_extended_json (doc, NULL);
                printf ("change received: %s\n", as_json);
                bson_free (as_json);
             }

             exit_code = EXIT_SUCCESS;

          cleanup:
             mongoc_uri_destroy (uri);
             bson_destroy (&pipeline);
             bson_destroy (&opts);
             if (cached_operation_time.value_type) {
                bson_value_destroy (&cached_operation_time);
             }
             mongoc_change_stream_destroy (stream);
             mongoc_collection_destroy (coll);
             mongoc_client_destroy (client);
             mongoc_cleanup ();
             return exit_code;
          }

   mongoc_client_encryption_t
   Synopsis
          typedef struct _mongoc_client_encryption_t mongoc_client_encryption_t;

       mongoc_client_encryption_t provides utility functions for In-Use Encryption.

   Thread Safety
       mongoc_client_encryption_t is NOT thread-safe and should only be used in the  same  thread
       as         the         mongoc_client_t         that        is        configured        via
       mongoc_client_encryption_opts_set_keyvault_client().

   Lifecycle
       The key vault client, configured via  mongoc_client_encryption_opts_set_keyvault_client(),
       must outlive the mongoc_client_encryption_t.

       SEE ALSO:
          mongoc_client_enable_auto_encryption()

          mongoc_client_pool_enable_auto_encryption()

          In-Use Encryption for libmongoc

          The MongoDB Manual for Client-Side Field Level Encryption

          The MongoDB Manual for Queryable Encryption

   mongoc_client_encryption_datakey_opts_t
   Synopsis
          typedef struct _mongoc_client_encryption_datakey_opts_t mongoc_client_encryption_datakey_opts_t;

       Used to set options for mongoc_client_encryption_create_datakey().

       SEE ALSO:
          mongoc_client_encryption_create_datakey()

   mongoc_client_encryption_rewrap_many_datakey_result_t
   Synopsis
          typedef struct _mongoc_client_encryption_rewrap_many_datakey_result_t
             mongoc_client_encryption_rewrap_many_datakey_result_t;

       Used to access the result of mongoc_client_encryption_rewrap_many_datakey().

       SEE ALSO:
          mongoc_client_encryption_rewrap_many_datakey()

   mongoc_client_encryption_encrypt_opts_t
   Synopsis
          typedef struct _mongoc_client_encryption_encrypt_opts_t mongoc_client_encryption_encrypt_opts_t;

       Used to set options for mongoc_client_encryption_encrypt().

       SEE ALSO:
          mongoc_client_encryption_encrypt()

   mongoc_client_encryption_encrypt_range_opts_t
   Synopsis
          typedef struct _mongoc_client_encryption_encrypt_range_opts_t mongoc_client_encryption_encrypt_range_opts_t;

       IMPORTANT:
          The Range algorithm is experimental only and not intended for public use. It is subject
          to breaking changes. This API is part of the experimental Queryable Encryption API  and
          may be subject to breaking changes in future releases.

       New in version 1.24.0.

       RangeOpts   specifies   index   options   for  a  Queryable  Encryption  field  supporting
       "rangePreview" queries. Used to set options for mongoc_client_encryption_encrypt().

       The options min, max, sparsity, and range must match the values set in the encryptedFields
       of the destination collection.

       For double and decimal128 fields, min/max/precision must all be set, or all be unset.

       SEE ALSO:
          mongoc_client_encryption_encrypt()
          mongoc_client_encryption_encrypt_opts_t

   mongoc_client_encryption_opts_t
   Synopsis
          typedef struct _mongoc_client_encryption_opts_t mongoc_client_encryption_opts_t;

       Used to set options for mongoc_client_encryption_new().

       SEE ALSO:
          mongoc_client_encryption_new()

   mongoc_client_pool_t
       A connection pool for multi-threaded programs. See Connection Pooling.

   Synopsis
          typedef struct _mongoc_client_pool_t mongoc_client_pool_t

       mongoc_client_pool_t  is  the  basis  for  multi-threading  in the MongoDB C driver. Since
       mongoc_client_t structures are not thread-safe, this structure is used to retrieve  a  new
       mongoc_client_t  for  a  given  thread.  This  structure  is  thread-safe,  except for its
       destructor method, mongoc_client_pool_destroy(), which is not thread-safe and must only be
       called from one thread.

   Example
       example-pool.c

          /* gcc example-pool.c -o example-pool $(pkg-config --cflags --libs
           * libmongoc-1.0) */

          /* ./example-pool [CONNECTION_STRING] */

          #include <mongoc/mongoc.h>
          #include <pthread.h>
          #include <stdio.h>

          static pthread_mutex_t mutex;
          static bool in_shutdown = false;

          static void *
          worker (void *data)
          {
             mongoc_client_pool_t *pool = data;
             mongoc_client_t *client;
             bson_t ping = BSON_INITIALIZER;
             bson_error_t error;
             bool r;

             BSON_APPEND_INT32 (&ping, "ping", 1);

             while (true) {
                client = mongoc_client_pool_pop (pool);
                /* Do something with client. If you are writing an HTTP server, you
                 * probably only want to hold onto the client for the portion of the
                 * request performing database queries.
                 */
                r = mongoc_client_command_simple (
                   client, "admin", &ping, NULL, NULL, &error);

                if (!r) {
                   fprintf (stderr, "%s\n", error.message);
                }

                mongoc_client_pool_push (pool, client);

                pthread_mutex_lock (&mutex);
                if (in_shutdown || !r) {
                   pthread_mutex_unlock (&mutex);
                   break;
                }

                pthread_mutex_unlock (&mutex);
             }

             bson_destroy (&ping);
             return NULL;
          }

          int
          main (int argc, char *argv[])
          {
             const char *uri_string = "mongodb://127.0.0.1/?appname=pool-example";
             mongoc_uri_t *uri;
             bson_error_t error;
             mongoc_client_pool_t *pool;
             pthread_t threads[10];
             unsigned i;
             void *ret;

             pthread_mutex_init (&mutex, NULL);
             mongoc_init ();

             if (argc > 1) {
                uri_string = argv[1];
             }

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             pool = mongoc_client_pool_new (uri);
             mongoc_client_pool_set_error_api (pool, 2);

             for (i = 0; i < 10; i++) {
                pthread_create (&threads[i], NULL, worker, pool);
             }

             sleep (10);
             pthread_mutex_lock (&mutex);
             in_shutdown = true;
             pthread_mutex_unlock (&mutex);

             for (i = 0; i < 10; i++) {
                pthread_join (threads[i], &ret);
             }

             mongoc_client_pool_destroy (pool);
             mongoc_uri_destroy (uri);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

   mongoc_client_session_t
       Use  a  session  for a sequence of operations, optionally with causal consistency. See the
       MongoDB Manual Entry for Causal Consistency.

   Synopsis
       Start a session with mongoc_client_start_session(), use the  session  for  a  sequence  of
       operations      and     multi-document     transactions,     then     free     it     with
       mongoc_client_session_destroy(). Any mongoc_cursor_t  or  mongoc_change_stream_t  using  a
       session  must  be destroyed before the session, and a session must be destroyed before the
       mongoc_client_t it came from.

       By default, sessions are  causally  consistent.  To  disable  causal  consistency,  before
       starting  a  session create a mongoc_session_opt_t with mongoc_session_opts_new() and call
       mongoc_session_opts_set_causal_consistency(),    then     free     the     struct     with
       mongoc_session_opts_destroy().

       Unacknowledged writes are prohibited with sessions.

       A  mongoc_client_session_t  must  be  used  by  only  one thread at a time. Due to session
       pooling, mongoc_client_start_session() may return a session that has been  idle  for  some
       time  and  is about to be closed after its idle timeout. Use the session within one minute
       of acquiring it to refresh the session and avoid a timeout.

   Fork Safety
       A mongoc_client_session_t is only usable in the parent process after  a  fork.  The  child
       process must call mongoc_client_reset() on the client field.

   Example
       example-session.c

          /* gcc example-session.c -o example-session \
           *     $(pkg-config --cflags --libs libmongoc-1.0) */

          /* ./example-session [CONNECTION_STRING] */

          #include <stdio.h>
          #include <mongoc/mongoc.h>

          int
          main (int argc, char *argv[])
          {
             int exit_code = EXIT_FAILURE;

             mongoc_client_t *client = NULL;
             const char *uri_string = "mongodb://127.0.0.1/?appname=session-example";
             mongoc_uri_t *uri = NULL;
             mongoc_client_session_t *client_session = NULL;
             mongoc_collection_t *collection = NULL;
             bson_error_t error;
             bson_t *selector = NULL;
             bson_t *update = NULL;
             bson_t *update_opts = NULL;
             bson_t *find_opts = NULL;
             mongoc_read_prefs_t *secondary = NULL;
             mongoc_cursor_t *cursor = NULL;
             const bson_t *doc;
             char *str;
             bool r;

             mongoc_init ();

             if (argc > 1) {
                uri_string = argv[1];
             }

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                goto done;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                goto done;
             }

             mongoc_client_set_error_api (client, 2);

             /* pass NULL for options - by default the session is causally consistent */
             client_session = mongoc_client_start_session (client, NULL, &error);
             if (!client_session) {
                fprintf (stderr, "Failed to start session: %s\n", error.message);
                goto done;
             }

             collection = mongoc_client_get_collection (client, "test", "collection");
             selector = BCON_NEW ("_id", BCON_INT32 (1));
             update = BCON_NEW ("$inc", "{", "x", BCON_INT32 (1), "}");
             update_opts = bson_new ();
             if (!mongoc_client_session_append (client_session, update_opts, &error)) {
                fprintf (stderr, "Could not add session to opts: %s\n", error.message);
                goto done;
             }

             r = mongoc_collection_update_one (
                collection, selector, update, update_opts, NULL /* reply */, &error);

             if (!r) {
                fprintf (stderr, "Update failed: %s\n", error.message);
                goto done;
             }

             bson_destroy (selector);
             selector = BCON_NEW ("_id", BCON_INT32 (1));
             secondary = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);

             find_opts = BCON_NEW ("maxTimeMS", BCON_INT32 (2000));
             if (!mongoc_client_session_append (client_session, find_opts, &error)) {
                fprintf (stderr, "Could not add session to opts: %s\n", error.message);
                goto done;
             };

             /* read from secondary. since we're in a causally consistent session, the
              * data is guaranteed to reflect the update we did on the primary. the query
              * blocks waiting for the secondary to catch up, if necessary, or times out
              * and fails after 2000 ms.
              */
             cursor = mongoc_collection_find_with_opts (
                collection, selector, find_opts, secondary);

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_json (doc, NULL);
                fprintf (stdout, "%s\n", str);
                bson_free (str);
             }

             if (mongoc_cursor_error (cursor, &error)) {
                fprintf (stderr, "Cursor Failure: %s\n", error.message);
                goto done;
             }

             exit_code = EXIT_SUCCESS;

          done:
             if (find_opts) {
                bson_destroy (find_opts);
             }
             if (update) {
                bson_destroy (update);
             }
             if (selector) {
                bson_destroy (selector);
             }
             if (update_opts) {
                bson_destroy (update_opts);
             }
             if (secondary) {
                mongoc_read_prefs_destroy (secondary);
             }
             /* destroy cursor, collection, session before the client they came from */
             if (cursor) {
                mongoc_cursor_destroy (cursor);
             }
             if (collection) {
                mongoc_collection_destroy (collection);
             }
             if (client_session) {
                mongoc_client_session_destroy (client_session);
             }
             if (uri) {
                mongoc_uri_destroy (uri);
             }
             if (client) {
                mongoc_client_destroy (client);
             }

             mongoc_cleanup ();

             return exit_code;
          }

   mongoc_client_session_with_transaction_cb_t
   Synopsis
          typedef bool (*mongoc_client_session_with_transaction_cb_t) (
             mongoc_client_session_t *session,
             void *ctx,
             bson_t **reply,
             bson_error_t *error);

       Provide this callback to mongoc_client_session_with_transaction(). The callback should run
       a sequence of operations meant to be contained within a transaction.  The callback  should
       not attempt to start or commit transactions.

   Parameterssession: A mongoc_client_session_t.

       • ctx:     A     void*     set    to    the    the    user-provided    ctx    passed    to
         mongoc_client_session_with_transaction().

       • reply: An optional location for a bson_t or NULL. The callback should  set  this  if  it
         runs any operations against the server and receives replies.

       • error:  A  bson_error_t.  The  callback  should set this if it receives any errors while
         running operations against the server.

   Return
       Returns true for success and false on failure. If cb returns false then it should also set
       error.

       SEE ALSO:
          mongoc_client_session_with_transaction()

   mongoc_client_t
       A single-threaded MongoDB connection. See Connection Pooling.

   Synopsis
          typedef struct _mongoc_client_t mongoc_client_t;

          typedef mongoc_stream_t *(*mongoc_stream_initiator_t) (
             const mongoc_uri_t *uri,
             const mongoc_host_list_t *host,
             void *user_data,
             bson_error_t *error);

       mongoc_client_t  is  an opaque type that provides access to a MongoDB server, replica set,
       or sharded  cluster.  It  maintains  management  of  underlying  sockets  and  routing  to
       individual nodes based on mongoc_read_prefs_t or mongoc_write_concern_t.

   Streams
       The  underlying transport for a given client can be customized, wrapped or replaced by any
       implementation  that  fulfills  mongoc_stream_t.  A  custom  transport  can  be  set  with
       mongoc_client_set_stream_initiator().

   Thread Safety
       mongoc_client_t is NOT thread-safe and should only be used from one thread at a time. When
       used in  multi-threaded  scenarios,  it  is  recommended  that  you  use  the  thread-safe
       mongoc_client_pool_t to retrieve a mongoc_client_t for your thread.

   Fork Safety
       A  mongoc_client_t  is  only  usable in the parent process after a fork. The child process
       must call mongoc_client_reset().

   Example
       example-client.c

          /* gcc example-client.c -o example-client $(pkg-config --cflags --libs
           * libmongoc-1.0) */

          /* ./example-client [CONNECTION_STRING [COLLECTION_NAME]] */

          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             mongoc_cursor_t *cursor;
             bson_error_t error;
             const bson_t *doc;
             const char *collection_name = "test";
             bson_t query;
             char *str;
             const char *uri_string = "mongodb://127.0.0.1/?appname=client-example";
             mongoc_uri_t *uri;

             mongoc_init ();
             if (argc > 1) {
                uri_string = argv[1];
             }

             if (argc > 2) {
                collection_name = argv[2];
             }

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);

             bson_init (&query);
             collection = mongoc_client_get_collection (client, "test", collection_name);
             cursor = mongoc_collection_find_with_opts (
                collection,
                &query,
                NULL,  /* additional options */
                NULL); /* read prefs, NULL for default */

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_canonical_extended_json (doc, NULL);
                fprintf (stdout, "%s\n", str);
                bson_free (str);
             }

             if (mongoc_cursor_error (cursor, &error)) {
                fprintf (stderr, "Cursor Failure: %s\n", error.message);
                return EXIT_FAILURE;
             }

             bson_destroy (&query);
             mongoc_cursor_destroy (cursor);
             mongoc_collection_destroy (collection);
             mongoc_uri_destroy (uri);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

   mongoc_collection_t
   Synopsis
          typedef struct _mongoc_collection_t mongoc_collection_t;

       mongoc_collection_t provides access to a MongoDB collection.  This handle  is  useful  for
       actions for most CRUD operations, I.e. insert, update, delete, find, etc.

   Read Preferences and Write Concerns
       Read  preferences  and  write  concerns  are inherited from the parent client. They can be
       overridden by set_* commands if so desired.

   mongoc_cursor_t
       Client-side cursor abstraction

   Synopsis
          typedef struct _mongoc_cursor_t mongoc_cursor_t;

       mongoc_cursor_t provides access to a MongoDB query cursor.  It wraps up the wire  protocol
       negotiation required to initiate a query and retrieve an unknown number of documents.

       Common cursor operations include:

       • Determine which host we've connected to with mongoc_cursor_get_host().

       • Retrieve more records with repeated calls to mongoc_cursor_next().

       • Clone a query to repeat execution at a later point with mongoc_cursor_clone().

       • Test for errors with mongoc_cursor_error().

       Cursors  are lazy, meaning that no connection is established and no network traffic occurs
       until the first call to mongoc_cursor_next().

   Thread Safety
       mongoc_cursor_t is NOT thread safe. It may only be used from within the thread in which it
       was created.

   Example
       Query MongoDB and iterate results

          /* gcc example-client.c -o example-client $(pkg-config --cflags --libs
           * libmongoc-1.0) */

          /* ./example-client [CONNECTION_STRING [COLLECTION_NAME]] */

          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_client_t *client;
             mongoc_collection_t *collection;
             mongoc_cursor_t *cursor;
             bson_error_t error;
             const bson_t *doc;
             const char *collection_name = "test";
             bson_t query;
             char *str;
             const char *uri_string = "mongodb://127.0.0.1/?appname=client-example";
             mongoc_uri_t *uri;

             mongoc_init ();
             if (argc > 1) {
                uri_string = argv[1];
             }

             if (argc > 2) {
                collection_name = argv[2];
             }

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);

             bson_init (&query);
             collection = mongoc_client_get_collection (client, "test", collection_name);
             cursor = mongoc_collection_find_with_opts (
                collection,
                &query,
                NULL,  /* additional options */
                NULL); /* read prefs, NULL for default */

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_canonical_extended_json (doc, NULL);
                fprintf (stdout, "%s\n", str);
                bson_free (str);
             }

             if (mongoc_cursor_error (cursor, &error)) {
                fprintf (stderr, "Cursor Failure: %s\n", error.message);
                return EXIT_FAILURE;
             }

             bson_destroy (&query);
             mongoc_cursor_destroy (cursor);
             mongoc_collection_destroy (collection);
             mongoc_uri_destroy (uri);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

   mongoc_database_t
       MongoDB Database Abstraction

   Synopsis
          typedef struct _mongoc_database_t mongoc_database_t;

       mongoc_database_t provides access to a MongoDB database. This handle is useful for actions
       a particular database object. It is not a container for mongoc_collection_t structures.

       Read preferences and write concerns are inherited from the  parent  client.  They  can  be
       overridden with mongoc_database_set_read_prefs() and mongoc_database_set_write_concern().

   Examples
          #include <mongoc/mongoc.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_database_t *database;
             mongoc_client_t *client;

             mongoc_init ();

             client = mongoc_client_new ("mongodb://localhost/");
             database = mongoc_client_get_database (client, "test");

             mongoc_database_destroy (database);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return 0;
          }

   mongoc_delete_flags_t
       WARNING:
          Deprecated  since  version  1.9.0: These flags are deprecated and should not be used in
          new code.

          Please use mongoc_collection_delete_one()  or  mongoc_collection_delete_many()  in  new
          code.

   Synopsis
          typedef enum {
             MONGOC_DELETE_NONE = 0,
             MONGOC_DELETE_SINGLE_REMOVE = 1 << 0,
          } mongoc_delete_flags_t;

       Flags for deletion operations

   mongoc_find_and_modify_opts_t
       find_and_modify abstraction

   Synopsis
       mongoc_find_and_modify_opts_t  is  a  builder  interface  to  construct  the findAndModify
       command.

       It was created to be able to accommodate new arguments to the findAndModify command.

       As of MongoDB 3.2, the mongoc_write_concern_t specified on the mongoc_collection_t will be
       used, if any.

   Example
       flags.c

          void
          fam_flags (mongoc_collection_t *collection)
          {
             mongoc_find_and_modify_opts_t *opts;
             bson_t reply;
             bson_error_t error;
             bson_t query = BSON_INITIALIZER;
             bson_t *update;
             bool success;

             /* Find Zlatan Ibrahimovic, the striker */
             BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
             BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
             BSON_APPEND_UTF8 (&query, "profession", "Football player");
             BSON_APPEND_INT32 (&query, "age", 34);
             BSON_APPEND_INT32 (
                &query, "goals", (16 + 35 + 23 + 57 + 16 + 14 + 28 + 84) + (1 + 6 + 62));

             /* Add his football position */
             update = BCON_NEW ("$set", "{", "position", BCON_UTF8 ("striker"), "}");

             opts = mongoc_find_and_modify_opts_new ();

             mongoc_find_and_modify_opts_set_update (opts, update);

             /* Create the document if it didn't exist, and return the updated document */
             mongoc_find_and_modify_opts_set_flags (
                opts, MONGOC_FIND_AND_MODIFY_UPSERT | MONGOC_FIND_AND_MODIFY_RETURN_NEW);

             success = mongoc_collection_find_and_modify_with_opts (
                collection, &query, opts, &reply, &error);

             if (success) {
                char *str;

                str = bson_as_canonical_extended_json (&reply, NULL);
                printf ("%s\n", str);
                bson_free (str);
             } else {
                fprintf (
                   stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__);
             }

             bson_destroy (&reply);
             bson_destroy (update);
             bson_destroy (&query);
             mongoc_find_and_modify_opts_destroy (opts);
          }

       bypass.c

          void
          fam_bypass (mongoc_collection_t *collection)
          {
             mongoc_find_and_modify_opts_t *opts;
             bson_t reply;
             bson_t *update;
             bson_error_t error;
             bson_t query = BSON_INITIALIZER;
             bool success;

             /* Find Zlatan Ibrahimovic, the striker */
             BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
             BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
             BSON_APPEND_UTF8 (&query, "profession", "Football player");

             /* Bump his age */
             update = BCON_NEW ("$inc", "{", "age", BCON_INT32 (1), "}");

             opts = mongoc_find_and_modify_opts_new ();
             mongoc_find_and_modify_opts_set_update (opts, update);
             /* He can still play, even though he is pretty old. */
             mongoc_find_and_modify_opts_set_bypass_document_validation (opts, true);

             success = mongoc_collection_find_and_modify_with_opts (
                collection, &query, opts, &reply, &error);

             if (success) {
                char *str;

                str = bson_as_canonical_extended_json (&reply, NULL);
                printf ("%s\n", str);
                bson_free (str);
             } else {
                fprintf (
                   stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__);
             }

             bson_destroy (&reply);
             bson_destroy (update);
             bson_destroy (&query);
             mongoc_find_and_modify_opts_destroy (opts);
          }

       update.c

          void
          fam_update (mongoc_collection_t *collection)
          {
             mongoc_find_and_modify_opts_t *opts;
             bson_t *update;
             bson_t reply;
             bson_error_t error;
             bson_t query = BSON_INITIALIZER;
             bool success;

             /* Find Zlatan Ibrahimovic */
             BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
             BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");

             /* Make him a book author */
             update = BCON_NEW ("$set", "{", "author", BCON_BOOL (true), "}");

             opts = mongoc_find_and_modify_opts_new ();
             /* Note that the document returned is the _previous_ version of the document
              * To fetch the modified new version, use
              * mongoc_find_and_modify_opts_set_flags (opts,
              * MONGOC_FIND_AND_MODIFY_RETURN_NEW);
              */
             mongoc_find_and_modify_opts_set_update (opts, update);

             success = mongoc_collection_find_and_modify_with_opts (
                collection, &query, opts, &reply, &error);

             if (success) {
                char *str;

                str = bson_as_canonical_extended_json (&reply, NULL);
                printf ("%s\n", str);
                bson_free (str);
             } else {
                fprintf (
                   stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__);
             }

             bson_destroy (&reply);
             bson_destroy (update);
             bson_destroy (&query);
             mongoc_find_and_modify_opts_destroy (opts);
          }

       fields.c

          void
          fam_fields (mongoc_collection_t *collection)
          {
             mongoc_find_and_modify_opts_t *opts;
             bson_t fields = BSON_INITIALIZER;
             bson_t *update;
             bson_t reply;
             bson_error_t error;
             bson_t query = BSON_INITIALIZER;
             bool success;

             /* Find Zlatan Ibrahimovic */
             BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
             BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");

             /* Return his goal tally */
             BSON_APPEND_INT32 (&fields, "goals", 1);

             /* Bump his goal tally */
             update = BCON_NEW ("$inc", "{", "goals", BCON_INT32 (1), "}");

             opts = mongoc_find_and_modify_opts_new ();
             mongoc_find_and_modify_opts_set_update (opts, update);
             mongoc_find_and_modify_opts_set_fields (opts, &fields);
             /* Return the new tally */
             mongoc_find_and_modify_opts_set_flags (opts,
                                                    MONGOC_FIND_AND_MODIFY_RETURN_NEW);

             success = mongoc_collection_find_and_modify_with_opts (
                collection, &query, opts, &reply, &error);

             if (success) {
                char *str;

                str = bson_as_canonical_extended_json (&reply, NULL);
                printf ("%s\n", str);
                bson_free (str);
             } else {
                fprintf (
                   stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__);
             }

             bson_destroy (&reply);
             bson_destroy (update);
             bson_destroy (&fields);
             bson_destroy (&query);
             mongoc_find_and_modify_opts_destroy (opts);
          }

       sort.c

          void
          fam_sort (mongoc_collection_t *collection)
          {
             mongoc_find_and_modify_opts_t *opts;
             bson_t *update;
             bson_t sort = BSON_INITIALIZER;
             bson_t reply;
             bson_error_t error;
             bson_t query = BSON_INITIALIZER;
             bool success;

             /* Find all users with the lastname Ibrahimovic */
             BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");

             /* Sort by age (descending) */
             BSON_APPEND_INT32 (&sort, "age", -1);

             /* Bump his goal tally */
             update = BCON_NEW ("$set", "{", "oldest", BCON_BOOL (true), "}");

             opts = mongoc_find_and_modify_opts_new ();
             mongoc_find_and_modify_opts_set_update (opts, update);
             mongoc_find_and_modify_opts_set_sort (opts, &sort);

             success = mongoc_collection_find_and_modify_with_opts (
                collection, &query, opts, &reply, &error);

             if (success) {
                char *str;

                str = bson_as_canonical_extended_json (&reply, NULL);
                printf ("%s\n", str);
                bson_free (str);
             } else {
                fprintf (
                   stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__);
             }

             bson_destroy (&reply);
             bson_destroy (update);
             bson_destroy (&sort);
             bson_destroy (&query);
             mongoc_find_and_modify_opts_destroy (opts);
          }

       opts.c

          void
          fam_opts (mongoc_collection_t *collection)
          {
             mongoc_find_and_modify_opts_t *opts;
             bson_t reply;
             bson_t *update;
             bson_error_t error;
             bson_t query = BSON_INITIALIZER;
             mongoc_write_concern_t *wc;
             bson_t extra = BSON_INITIALIZER;
             bool success;

             /* Find Zlatan Ibrahimovic, the striker */
             BSON_APPEND_UTF8 (&query, "firstname", "Zlatan");
             BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic");
             BSON_APPEND_UTF8 (&query, "profession", "Football player");

             /* Bump his age */
             update = BCON_NEW ("$inc", "{", "age", BCON_INT32 (1), "}");

             opts = mongoc_find_and_modify_opts_new ();
             mongoc_find_and_modify_opts_set_update (opts, update);

             /* Abort if the operation takes too long. */
             mongoc_find_and_modify_opts_set_max_time_ms (opts, 100);

             /* Set write concern w: 2 */
             wc = mongoc_write_concern_new ();
             mongoc_write_concern_set_w (wc, 2);
             mongoc_write_concern_append (wc, &extra);

             /* Some future findAndModify option the driver doesn't support conveniently
              */
             BSON_APPEND_INT32 (&extra, "futureOption", 42);
             mongoc_find_and_modify_opts_append (opts, &extra);

             success = mongoc_collection_find_and_modify_with_opts (
                collection, &query, opts, &reply, &error);

             if (success) {
                char *str;

                str = bson_as_canonical_extended_json (&reply, NULL);
                printf ("%s\n", str);
                bson_free (str);
             } else {
                fprintf (
                   stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__);
             }

             bson_destroy (&reply);
             bson_destroy (&extra);
             bson_destroy (update);
             bson_destroy (&query);
             mongoc_write_concern_destroy (wc);
             mongoc_find_and_modify_opts_destroy (opts);
          }

       fam.c

          int
          main (void)
          {
             mongoc_collection_t *collection;
             mongoc_database_t *database;
             mongoc_client_t *client;
             const char *uri_string =
                "mongodb://localhost:27017/admin?appname=find-and-modify-opts-example";
             mongoc_uri_t *uri;
             bson_error_t error;
             bson_t *options;

             mongoc_init ();

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                return EXIT_FAILURE;
             }

             mongoc_client_set_error_api (client, 2);
             database = mongoc_client_get_database (client, "databaseName");

             options = BCON_NEW ("validator",
                                 "{",
                                 "age",
                                 "{",
                                 "$lte",
                                 BCON_INT32 (34),
                                 "}",
                                 "}",
                                 "validationAction",
                                 BCON_UTF8 ("error"),
                                 "validationLevel",
                                 BCON_UTF8 ("moderate"));

             collection = mongoc_database_create_collection (
                database, "collectionName", options, &error);
             if (!collection) {
                fprintf (
                   stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__);
                return EXIT_FAILURE;
             }

             fam_flags (collection);
             fam_bypass (collection);
             fam_update (collection);
             fam_fields (collection);
             fam_opts (collection);
             fam_sort (collection);

             mongoc_collection_drop (collection, NULL);
             bson_destroy (options);
             mongoc_uri_destroy (uri);
             mongoc_database_destroy (database);
             mongoc_collection_destroy (collection);
             mongoc_client_destroy (client);

             mongoc_cleanup ();
             return EXIT_SUCCESS;
          }

       Outputs:

          {
              "lastErrorObject": {
                  "updatedExisting": false,
                  "n": 1,
                  "upserted": {
                      "$oid": "56562a99d13e6d86239c7b00"
                  }
              },
              "value": {
                  "_id": {
                      "$oid": "56562a99d13e6d86239c7b00"
                  },
                  "age": 34,
                  "firstname": "Zlatan",
                  "goals": 342,
                  "lastname": "Ibrahimovic",
                  "profession": "Football player",
                  "position": "striker"
              },
              "ok": 1
          }
          {
              "lastErrorObject": {
                  "updatedExisting": true,
                  "n": 1
              },
              "value": {
                  "_id": {
                      "$oid": "56562a99d13e6d86239c7b00"
                  },
                  "age": 34,
                  "firstname": "Zlatan",
                  "goals": 342,
                  "lastname": "Ibrahimovic",
                  "profession": "Football player",
                  "position": "striker"
              },
              "ok": 1
          }
          {
              "lastErrorObject": {
                  "updatedExisting": true,
                  "n": 1
              },
              "value": {
                  "_id": {
                      "$oid": "56562a99d13e6d86239c7b00"
                  },
                  "age": 35,
                  "firstname": "Zlatan",
                  "goals": 342,
                  "lastname": "Ibrahimovic",
                  "profession": "Football player",
                  "position": "striker"
              },
              "ok": 1
          }
          {
              "lastErrorObject": {
                  "updatedExisting": true,
                  "n": 1
              },
              "value": {
                  "_id": {
                      "$oid": "56562a99d13e6d86239c7b00"
                  },
                  "goals": 343
              },
              "ok": 1
          }
          {
              "lastErrorObject": {
                  "updatedExisting": true,
                  "n": 1
              },
              "value": {
                  "_id": {
                      "$oid": "56562a99d13e6d86239c7b00"
                  },
                  "age": 35,
                  "firstname": "Zlatan",
                  "goals": 343,
                  "lastname": "Ibrahimovic",
                  "profession": "Football player",
                  "position": "striker",
                  "author": true
              },
              "ok": 1
          }

   mongoc_gridfs_file_list_t
   Synopsis
          #include <mongoc/mongoc.h>

          typedef struct _mongoc_gridfs_file_list_t mongoc_gridfs_file_list_t;

   Description
       mongoc_gridfs_file_list_t  provides a gridfs file list abstraction.  It provides iteration
       and basic marshalling on top of a regular mongoc_collection_find_with_opts() style  query.
       In interface, it's styled after mongoc_cursor_t.

   Example
          mongoc_gridfs_file_list_t *list;
          mongoc_gridfs_file_t *file;

          list = mongoc_gridfs_find (gridfs, query);

          while ((file = mongoc_gridfs_file_list_next (list))) {
             do_something (file);

             mongoc_gridfs_file_destroy (file);
          }

          mongoc_gridfs_file_list_destroy (list);

   mongoc_gridfs_file_opt_t
   Synopsis
          typedef struct {
             const char *md5;
             const char *filename;
             const char *content_type;
             const bson_t *aliases;
             const bson_t *metadata;
             uint32_t chunk_size;
          } mongoc_gridfs_file_opt_t;

   Description
       This  structure contains options that can be set on a mongoc_gridfs_file_t. It can be used
       by various functions when creating a new gridfs file.

   mongoc_gridfs_file_t
   Synopsis
          typedef struct _mongoc_gridfs_file_t mongoc_gridfs_file_t;

   Description
       This structure provides a MongoDB GridFS file abstraction. It provides several APIs.

       • readv, writev, seek, and tell.

       • General file metadata such as filename and length.

       • GridFS metadata such as md5, filename, content_type, aliases, metadata, chunk_size,  and
         upload_date.

   Thread Safety
       This structure is NOT thread-safe and should only be used from one thread at a time.

   Relatedmongoc_client_tmongoc_gridfs_tmongoc_gridfs_file_list_tmongoc_gridfs_file_opt_t

   mongoc_gridfs_bucket_t
   Synopsis
          #include <mongoc/mongoc.h>

          typedef struct _mongoc_gridfs_bucket_t mongoc_gridfs_bucket_t;

   Description
       mongoc_gridfs_bucket_t   provides   a   spec-compliant   MongoDB   GridFS  implementation,
       superseding mongoc_gridfs_t. See the GridFS MongoDB documentation.

   Thread Safety
       mongoc_gridfs_bucket_t is NOT thread-safe and should only be used in the  same  thread  as
       the owning mongoc_client_t.

   Lifecycle
       It  is  an  error to free a mongoc_gridfs_bucket_t before freeing all derived instances of
       mongoc_stream_t. The owning mongoc_client_t must outlive the mongoc_gridfs_bucket_t.

   Example
       example-gridfs-bucket.c

          #include <stdio.h>
          #include <stdlib.h>

          #include <mongoc/mongoc.h>

          int
          main (int argc, char *argv[])
          {
             const char *uri_string =
                "mongodb://localhost:27017/?appname=new-gridfs-example";
             mongoc_client_t *client;
             mongoc_database_t *db;
             mongoc_stream_t *file_stream;
             mongoc_gridfs_bucket_t *bucket;
             mongoc_cursor_t *cursor;
             bson_t filter;
             bool res;
             bson_value_t file_id;
             bson_error_t error;
             const bson_t *doc;
             char *str;
             mongoc_init ();

             if (argc != 3) {
                fprintf (stderr, "usage: %s SOURCE_FILE_PATH FILE_COPY_PATH\n", argv[0]);
                return EXIT_FAILURE;
             }

             /* 1. Make a bucket. */
             client = mongoc_client_new (uri_string);
             db = mongoc_client_get_database (client, "test");
             bucket = mongoc_gridfs_bucket_new (db, NULL, NULL, &error);
             if (!bucket) {
                printf ("Error creating gridfs bucket: %s\n", error.message);
                return EXIT_FAILURE;
             }

             /* 2. Insert a file.  */
             file_stream = mongoc_stream_file_new_for_path (argv[1], O_RDONLY, 0);
             res = mongoc_gridfs_bucket_upload_from_stream (
                bucket, "my-file", file_stream, NULL, &file_id, &error);
             if (!res) {
                printf ("Error uploading file: %s\n", error.message);
                return EXIT_FAILURE;
             }

             mongoc_stream_close (file_stream);
             mongoc_stream_destroy (file_stream);

             /* 3. Download the file in GridFS to a local file. */
             file_stream = mongoc_stream_file_new_for_path (argv[2], O_CREAT | O_RDWR, 0);
             if (!file_stream) {
                perror ("Error opening file stream");
                return EXIT_FAILURE;
             }

             res = mongoc_gridfs_bucket_download_to_stream (
                bucket, &file_id, file_stream, &error);
             if (!res) {
                printf ("Error downloading file to stream: %s\n", error.message);
                return EXIT_FAILURE;
             }
             mongoc_stream_close (file_stream);
             mongoc_stream_destroy (file_stream);

             /* 4. List what files are available in GridFS. */
             bson_init (&filter);
             cursor = mongoc_gridfs_bucket_find (bucket, &filter, NULL);

             while (mongoc_cursor_next (cursor, &doc)) {
                str = bson_as_canonical_extended_json (doc, NULL);
                printf ("%s\n", str);
                bson_free (str);
             }

             /* 5. Delete the file that we added. */
             res = mongoc_gridfs_bucket_delete_by_id (bucket, &file_id, &error);
             if (!res) {
                printf ("Error deleting the file: %s\n", error.message);
                return EXIT_FAILURE;
             }

             /* 6. Cleanup. */
             mongoc_stream_close (file_stream);
             mongoc_stream_destroy (file_stream);
             mongoc_cursor_destroy (cursor);
             bson_destroy (&filter);
             mongoc_gridfs_bucket_destroy (bucket);
             mongoc_database_destroy (db);
             mongoc_client_destroy (client);
             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       SEE ALSO:
          The MongoDB GridFS specification.

          The non spec-compliant mongoc_gridfs_t.

   mongoc_gridfs_t
       WARNING:
          This GridFS implementation does not conform to the MongoDB GridFS specification. For  a
          spec compliant implementation, use mongoc_gridfs_bucket_t.

   Synopsis
          #include <mongoc/mongoc.h>

          typedef struct _mongoc_gridfs_t mongoc_gridfs_t;

   Description
       mongoc_gridfs_t provides a MongoDB gridfs implementation. The system as a whole is made up
       of gridfs objects, which contain gridfs_files and gridfs_file_lists.  Essentially, a basic
       file system API.

       There  are  extensive  caveats  about  the  kind  of use cases gridfs is practical for. In
       particular, any writing after initial file creation is likely to both break any concurrent
       readers  and  be  quite expensive. That said, this implementation does allow for arbitrary
       writes to existing gridfs object, just use them with caution.

       mongoc_gridfs also integrates tightly with the mongoc_stream_t abstraction, which provides
       some  convenient  wrapping for file creation and reading/writing.  It can be used without,
       but its worth looking to see if your problem can fit that model.

       WARNING:
          mongoc_gridfs_t does not support read preferences. In a replica set, GridFS queries are
          always routed to the primary.

   Thread Safety
       mongoc_gridfs_t  is  NOT  thread-safe  and  should  only be used in the same thread as the
       owning mongoc_client_t.

   Lifecycle
       It is an error  to  free  a  mongoc_gridfs_t  before  freeing  all  related  instances  of
       mongoc_gridfs_file_t and mongoc_gridfs_file_list_t.

   Example
       example-gridfs.c

          #include <assert.h>
          #include <mongoc/mongoc.h>
          #include <stdio.h>
          #include <stdlib.h>
          #include <fcntl.h>

          int
          main (int argc, char *argv[])
          {
             mongoc_gridfs_t *gridfs;
             mongoc_gridfs_file_t *file;
             mongoc_gridfs_file_list_t *list;
             mongoc_gridfs_file_opt_t opt = {0};
             mongoc_client_t *client;
             const char *uri_string = "mongodb://127.0.0.1:27017/?appname=gridfs-example";
             mongoc_uri_t *uri;
             mongoc_stream_t *stream;
             bson_t filter;
             bson_t opts;
             bson_t child;
             bson_error_t error;
             ssize_t r;
             char buf[4096];
             mongoc_iovec_t iov;
             const char *filename;
             const char *command;
             bson_value_t id;

             if (argc < 2) {
                fprintf (stderr, "usage - %s command ...\n", argv[0]);
                return EXIT_FAILURE;
             }

             mongoc_init ();

             iov.iov_base = (void *) buf;
             iov.iov_len = sizeof buf;

             /* connect to localhost client */
             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             assert (client);
             mongoc_client_set_error_api (client, 2);

             /* grab a gridfs handle in test prefixed by fs */
             gridfs = mongoc_client_get_gridfs (client, "test", "fs", &error);
             assert (gridfs);

             command = argv[1];
             filename = argv[2];

             if (strcmp (command, "read") == 0) {
                if (argc != 3) {
                   fprintf (stderr, "usage - %s read filename\n", argv[0]);
                   return EXIT_FAILURE;
                }
                file = mongoc_gridfs_find_one_by_filename (gridfs, filename, &error);
                assert (file);

                stream = mongoc_stream_gridfs_new (file);
                assert (stream);

                for (;;) {
                   r = mongoc_stream_readv (stream, &iov, 1, -1, 0);

                   assert (r >= 0);

                   if (r == 0) {
                      break;
                   }

                   if (fwrite (iov.iov_base, 1, r, stdout) != r) {
                      MONGOC_ERROR ("Failed to write to stdout. Exiting.\n");
                      exit (1);
                   }
                }

                mongoc_stream_destroy (stream);
                mongoc_gridfs_file_destroy (file);
             } else if (strcmp (command, "list") == 0) {
                bson_init (&filter);

                bson_init (&opts);
                bson_append_document_begin (&opts, "sort", -1, &child);
                BSON_APPEND_INT32 (&child, "filename", 1);
                bson_append_document_end (&opts, &child);

                list = mongoc_gridfs_find_with_opts (gridfs, &filter, &opts);

                bson_destroy (&filter);
                bson_destroy (&opts);

                while ((file = mongoc_gridfs_file_list_next (list))) {
                   const char *name = mongoc_gridfs_file_get_filename (file);
                   printf ("%s\n", name ? name : "?");

                   mongoc_gridfs_file_destroy (file);
                }

                mongoc_gridfs_file_list_destroy (list);
             } else if (strcmp (command, "write") == 0) {
                if (argc != 4) {
                   fprintf (stderr, "usage - %s write filename input_file\n", argv[0]);
                   return EXIT_FAILURE;
                }

                stream = mongoc_stream_file_new_for_path (argv[3], O_RDONLY, 0);
                assert (stream);

                opt.filename = filename;

                /* the driver generates a file_id for you */
                file = mongoc_gridfs_create_file_from_stream (gridfs, stream, &opt);
                assert (file);

                id.value_type = BSON_TYPE_INT32;
                id.value.v_int32 = 1;

                /* optional: the following method specifies a file_id of any
                   BSON type */
                if (!mongoc_gridfs_file_set_id (file, &id, &error)) {
                   fprintf (stderr, "%s\n", error.message);
                   return EXIT_FAILURE;
                }

                if (!mongoc_gridfs_file_save (file)) {
                   mongoc_gridfs_file_error (file, &error);
                   fprintf (stderr, "Could not save: %s\n", error.message);
                   return EXIT_FAILURE;
                }

                mongoc_gridfs_file_destroy (file);
             } else {
                fprintf (stderr, "Unknown command");
                return EXIT_FAILURE;
             }

             mongoc_gridfs_destroy (gridfs);
             mongoc_uri_destroy (uri);
             mongoc_client_destroy (client);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       SEE ALSO:
          The MongoDB GridFS specification.

          The spec-compliant mongoc_gridfs_bucket_t.

   mongoc_host_list_t
   Synopsis
          typedef struct {
             mongoc_host_list_t *next;
             char host[BSON_HOST_NAME_MAX + 1];
             char host_and_port[BSON_HOST_NAME_MAX + 7];
             uint16_t port;
             int family;
             void *padding[4];
          } mongoc_host_list_t;

   Description
       The  host  and  port  of  a  MongoDB server. Can be part of a linked list: for example the
       return value of mongoc_uri_get_hosts() when multiple hosts are  provided  in  the  MongoDB
       URI.

       SEE ALSO:
          mongoc_uri_get_hosts() and mongoc_cursor_get_host().

   mongoc_index_opt_geo_t
   Synopsis
          #include <mongoc/mongoc.h>

          typedef struct {
             uint8_t twod_sphere_version;
             uint8_t twod_bits_precision;
             double twod_location_min;
             double twod_location_max;
             double haystack_bucket_size;
             uint8_t *padding[32];
          } mongoc_index_opt_geo_t;

   Description
       This structure contains the options that may be used for tuning a GEO index.

       SEE ALSO:
          mongoc_index_opt_t

          mongoc_index_opt_wt_t

   mongoc_index_opt_t
       WARNING:
          Deprecated  since version 1.8.0: This structure is deprecated and should not be used in
          new code. See Manage Collection Indexes.

   Synopsis
          #include <mongoc/mongoc.h>

          typedef struct {
             bool is_initialized;
             bool background;
             bool unique;
             const char *name;
             bool drop_dups;
             bool sparse;
             int32_t expire_after_seconds;
             int32_t v;
             const bson_t *weights;
             const char *default_language;
             const char *language_override;
             mongoc_index_opt_geo_t *geo_options;
             mongoc_index_opt_storage_t *storage_options;
             const bson_t *partial_filter_expression;
             const bson_t *collation;
             void *padding[4];
          } mongoc_index_opt_t;

   Description
       This structure contains the options that may be used for tuning a specific index.

       See the createIndexes documentations in the MongoDB manual for descriptions of  individual
       options.

       NOTE:
          dropDups is deprecated as of MongoDB version 3.0.0.  This option is silently ignored by
          the server and unique index builds using this option will fail if a duplicate value  is
          detected.

   Example
          {
             bson_t keys;
             bson_error_t error;
             mongoc_index_opt_t opt;
             mongoc_index_opt_geo_t geo_opt;

             mongoc_index_opt_init (&opt);
             mongoc_index_opt_geo_init (&geo_opt);

             bson_init (&keys);
             BSON_APPEND_UTF8 (&keys, "location", "2d");

             geo_opt.twod_location_min = -123;
             geo_opt.twod_location_max = +123;
             geo_opt.twod_bits_precision = 30;
             opt.geo_options = &geo_opt;

             collection = mongoc_client_get_collection (client, "test", "geo_test");
             if (mongoc_collection_create_index (collection, &keys, &opt, &error)) {
                /* Successfully created the geo index */
             }
             bson_destroy (&keys);
             mongoc_collection_destroy (&collection);
          }

       SEE ALSO:
          mongoc_index_opt_geo_t

          mongoc_index_opt_wt_t

   mongoc_index_opt_wt_t
   Synopsis
          #include <mongoc/mongoc.h>

          typedef struct {
             mongoc_index_opt_storage_t base;
             const char *config_str;
             void *padding[8];
          } mongoc_index_opt_wt_t;

   Description
       This  structure  contains  the  options  that may be used for tuning a WiredTiger specific
       index.

       SEE ALSO:
          mongoc_index_opt_t

          mongoc_index_opt_geo_t

   mongoc_insert_flags_t
       Flags for insert operations

   Synopsis
          typedef enum {
             MONGOC_INSERT_NONE = 0,
             MONGOC_INSERT_CONTINUE_ON_ERROR = 1 << 0,
          } mongoc_insert_flags_t;

          #define MONGOC_INSERT_NO_VALIDATE (1U << 31)

   Description
       These flags correspond to the MongoDB wire protocol. They may be  bitwise  or'd  together.
       They may modify how an insert happens on the MongoDB server.

   Flag Values
                  ┌────────────────────────────────┬──────────────────────────────────┐
                  │MONGOC_INSERT_NONE              │ Specify no insert flags.         │
                  ├────────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_INSERT_CONTINUE_ON_ERROR │ Continue   inserting   documents │
                  │                                │ from the insertion set  even  if │
                  │                                │ one insert fails.                │
                  ├────────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_INSERT_NO_VALIDATE       │ Do    not   validate   insertion │
                  │                                │ documents before  performing  an │
                  │                                │ insert.    Validation   can   be │
                  │                                │ expensive, so this can save some │
                  │                                │ time  if you know your documents │
                  │                                │ are already valid.               │
                  └────────────────────────────────┴──────────────────────────────────┘

   mongoc_iovec_t
   Synopsis
   Synopsis
          #include <mongoc/mongoc.h>

          #ifdef _WIN32
          typedef struct {
             u_long iov_len;
             char *iov_base;
          } mongoc_iovec_t;
          #else
          typedef struct iovec mongoc_iovec_t;
          #endif

       The  mongoc_iovec_t  structure  is  a  portability  abstraction  for  consumers   of   the
       mongoc_stream_t interfaces. It allows for scatter/gather I/O through the socket subsystem.

       WARNING:
          When  writing portable code, beware of the ordering of iov_len and iov_base as they are
          different on various platforms. Therefore,  you  should  not  use  C  initializers  for
          initialization.

   mongoc_optional_t
       A struct to store optional boolean values.

   Synopsis
       Used to specify optional boolean flags, which may remain unset.

       This is used within mongoc_server_api_t to track whether a flag was explicitly set.

   mongoc_query_flags_t
       Flags for query operations

   Synopsis
          typedef enum {
             MONGOC_QUERY_NONE = 0,
             MONGOC_QUERY_TAILABLE_CURSOR = 1 << 1,
             MONGOC_QUERY_SECONDARY_OK = 1 << 2,
             MONGOC_QUERY_OPLOG_REPLAY = 1 << 3,
             MONGOC_QUERY_NO_CURSOR_TIMEOUT = 1 << 4,
             MONGOC_QUERY_AWAIT_DATA = 1 << 5,
             MONGOC_QUERY_EXHAUST = 1 << 6,
             MONGOC_QUERY_PARTIAL = 1 << 7,
          } mongoc_query_flags_t;

   Description
       These  flags  correspond  to the MongoDB wire protocol. They may be bitwise or'd together.
       They may modify how a query is performed in the MongoDB server.

   Flag Values
                  ┌───────────────────────────────┬──────────────────────────────────┐
                  │MONGOC_QUERY_NONE              │ Specify no query flags.          │
                  ├───────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_QUERY_TAILABLE_CURSOR   │ Cursor will not be  closed  when │
                  │                               │ the  last data is retrieved. You │
                  │                               │ can resume this cursor later.    │
                  ├───────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_QUERY_SECONDARY_OK      │ Allow  query  of   replica   set │
                  │                               │ secondaries.                     │
                  ├───────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_QUERY_OPLOG_REPLAY      │ Used internally by MongoDB.      │
                  ├───────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_QUERY_NO_CURSOR_TIMEOUT │ The server normally times out an │
                  │                               │ idle cursor after an  inactivity │
                  │                               │ period    (10   minutes).   This │
                  │                               │ prevents that.                   │
                  ├───────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_QUERY_AWAIT_DATA        │ Use                         with │
                  │                               │ MONGOC_QUERY_TAILABLE_CURSOR.    │
                  │                               │ Block rather than  returning  no │
                  │                               │ data. After a period, time out.  │
                  ├───────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_QUERY_EXHAUST           │ Stream  the data down full blast │
                  │                               │ in  multiple  "reply"   packets. │
                  │                               │ Faster when you are pulling down │
                  │                               │ a lot of data and you  know  you │
                  │                               │ want  to  retrieve it all.  Only │
                  │                               │ applies to cursors created  from │
                  │                               │ a     find    operation    (i.e. │
                  │                               │ mongoc_collection_find()).       │
                  ├───────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_QUERY_PARTIAL           │ Get partial results from  mongos │
                  │                               │ if some shards are down (instead │
                  │                               │ of throwing an error).           │
                  └───────────────────────────────┴──────────────────────────────────┘

   mongoc_rand
       MongoDB Random Number Generator

   Synopsis
          void
          mongoc_rand_add (const void *buf, int num, double entropy);

          void
          mongoc_rand_seed (const void *buf, int num);

          int
          mongoc_rand_status (void);

   Description
       The mongoc_rand family of functions provide access to the low level randomness  primitives
       used   by   the   MongoDB   C  Driver.   In  particular,  they  control  the  creation  of
       cryptographically strong pseudo-random bytes required by some security mechanisms.

       While we can usually pull enough entropy from the environment, you may be required to seed
       the  PRNG  manually  depending on your OS, hardware and other entropy consumers running on
       the same system.

   Entropy
       mongoc_rand_add and mongoc_rand_seed allow the user to  directly  provide  entropy.   They
       differ  insofar  as  mongoc_rand_seed  requires  that  each  bit provided is fully random.
       mongoc_rand_add allows the user to specify the degree of randomness in the provided  bytes
       as well.

   Status
       The  mongoc_rand_status  function  allows the user to check the status of the mongoc PRNG.
       This can be used to guarantee sufficient entropy at program startup, rather  than  waiting
       for runtime errors to occur.

   mongoc_read_concern_t
       Read Concern abstraction

   Synopsis
       New in MongoDB 3.2.

       The  mongoc_read_concern_t  allows clients to choose a level of isolation for their reads.
       The  default,  MONGOC_READ_CONCERN_LEVEL_LOCAL,  is  right  for  the  great  majority   of
       applications.

       You  can  specify  a  read  concern on connection objects, database objects, or collection
       objects.

       See readConcern on the MongoDB website for more information.

       Read  Concern  is  only  sent  to  MongoDB  when   it   has   explicitly   been   set   by
       mongoc_read_concern_set_level() to anything other than NULL.

   Read Concern Levels
       ┌───────────────────────────────────────┬──────────────────────────┬───────────────────────┐
       │Macro                                  │ Description              │ First MongoDB version │
       ├───────────────────────────────────────┼──────────────────────────┼───────────────────────┤
       │MONGOC_READ_CONCERN_LEVEL_LOCAL        │ Level    "local",    the │ 3.2                   │
       │                                       │ default.                 │                       │
       ├───────────────────────────────────────┼──────────────────────────┼───────────────────────┤
       │MONGOC_READ_CONCERN_LEVEL_MAJORITY     │ Level "majority".        │ 3.2                   │
       ├───────────────────────────────────────┼──────────────────────────┼───────────────────────┤
       │MONGOC_READ_CONCERN_LEVEL_LINEARIZABLE │ Level "linearizable".    │ 3.4                   │
       ├───────────────────────────────────────┼──────────────────────────┼───────────────────────┤
       │MONGOC_READ_CONCERN_LEVEL_AVAILABLE    │ Level "available".       │ 3.6                   │
       ├───────────────────────────────────────┼──────────────────────────┼───────────────────────┤
       │MONGOC_READ_CONCERN_LEVEL_SNAPSHOT     │ Level "snapshot".        │ 4.0                   │
       └───────────────────────────────────────┴──────────────────────────┴───────────────────────┘

       For     the    sake    of    compatibility    with    future    versions    of    MongoDB,
       mongoc_read_concern_set_level() allows any string,  not  just  this  list  of  known  read
       concern levels.

       See  Read  Concern  Levels in the MongoDB manual for more information about the individual
       read concern levels.

   mongoc_read_mode_t
       Read Preference Modes

   Synopsis
          typedef enum {
             MONGOC_READ_PRIMARY = (1 << 0),
             MONGOC_READ_SECONDARY = (1 << 1),
             MONGOC_READ_PRIMARY_PREFERRED = (1 << 2) | MONGOC_READ_PRIMARY,
             MONGOC_READ_SECONDARY_PREFERRED = (1 << 2) | MONGOC_READ_SECONDARY,
             MONGOC_READ_NEAREST = (1 << 3) | MONGOC_READ_SECONDARY,
          } mongoc_read_mode_t;

   Description
       This enum describes how reads should be dispatched. The default is MONGOC_READ_PRIMARY.

       Please see the MongoDB website for a description of Read Preferences.

   mongoc_read_prefs_t
       A read preference abstraction

   Synopsis
       mongoc_read_prefs_t provides  an  abstraction  on  top  of  the  MongoDB  connection  read
       preferences.  It  allows  for hinting to the driver which nodes in a replica set should be
       accessed first and how.

       You can specify a read preference mode on connection objects, database objects, collection
       objects,  or  per-operation.   Generally, it makes the most sense to stick with the global
       default mode, MONGOC_READ_PRIMARY.  All of the other modes come with caveats that won't be
       covered in great detail here.

   Read Modes
                  ┌────────────────────────────────┬──────────────────────────────────┐
                  │MONGOC_READ_PRIMARY             │ Default   mode.  All  operations │
                  │                                │ read from  the  current  replica │
                  │                                │ set primary.                     │
                  ├────────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_READ_SECONDARY           │ All  operations  read from among │
                  │                                │ the nearest secondary members of │
                  │                                │ the replica set.                 │
                  ├────────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_READ_PRIMARY_PREFERRED   │ In  most  situations, operations │
                  │                                │ read from the primary but if  it │
                  │                                │ is  unavailable, operations read │
                  │                                │ from secondary members.          │
                  ├────────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_READ_SECONDARY_PREFERRED │ In most  situations,  operations │
                  │                                │ read   from  among  the  nearest │
                  │                                │ secondary  members,  but  if  no │
                  │                                │ secondaries    are    available, │
                  │                                │ operations   read    from    the │
                  │                                │ primary.                         │
                  ├────────────────────────────────┼──────────────────────────────────┤
                  │MONGOC_READ_NEAREST             │ Operations  read  from among the │
                  │                                │ nearest members of  the  replica │
                  │                                │ set,    irrespective    of   the │
                  │                                │ member's type.                   │
                  └────────────────────────────────┴──────────────────────────────────┘

   Tag Sets
       Tag sets allow you to specify custom read preferences and  write  concerns  so  that  your
       application can target operations to specific members.

       Custom  read  preferences  and  write  concerns evaluate tags sets in different ways: read
       preferences consider the value of a tag when selecting a member to read from, while  write
       concerns  ignore the value of a tag when selecting a member, except to consider whether or
       not the value is unique.

       You can specify tag sets with the following read preference modes:

       • primaryPreferred

       • secondary

       • secondaryPreferred

       • nearest

       Tags are not  compatible  with  MONGOC_READ_PRIMARY  and,  in  general,  only  apply  when
       selecting  a  secondary  member  of  a set for a read operation. However, the nearest read
       mode, when combined with a tag set, will  select  the  nearest  member  that  matches  the
       specified tag set, which may be a primary or secondary.

       Tag sets are represented as a comma-separated list of colon-separated key-value pairs when
       provided as a connection string, e.g. dc:ny,rack:1.

       To specify a list of tag sets, using multiple readPreferenceTags, e.g.

          readPreferenceTags=dc:ny,rack:1;readPreferenceTags=dc:ny;readPreferenceTags=

       Note the empty value for the last one, which means "match any secondary as a last resort".

       Order matters when using multiple readPreferenceTags.

       Tag Sets can also be configured using mongoc_read_prefs_set_tags().

       All interfaces use the same member selection logic to choose the member to which to direct
       read operations, basing the choice on read preference mode and tag sets.

   Max Staleness
       When  connected  to  replica  set  running  MongoDB 3.4 or later, the driver estimates the
       staleness of each secondary  based  on  lastWriteDate  values  provided  in  server  hello
       responses.

       Max Staleness is the maximum replication lag in seconds (wall clock time) that a secondary
       can suffer and still be eligible for reads. The default is MONGOC_NO_MAX_STALENESS,  which
       disables   staleness   checks.   Otherwise,  it  must  be  a  positive  integer  at  least
       MONGOC_SMALLEST_MAX_STALENESS_SECONDS (90 seconds).

       Max Staleness is also supported by sharded clusters of replica sets  if  all  servers  run
       MongoDB 3.4 or later.

   Hedged Reads
       When  connecting  to  a sharded cluster running MongoDB 4.4 or later, reads can be sent in
       parallel to the two  "best"  hosts.   Once  one  result  returns,  any  other  outstanding
       operations that were part of the hedged read are cancelled.

       When  the  read  preference mode is MONGOC_READ_NEAREST and the sharded cluster is running
       MongoDB 4.4 or later, hedged reads are enabled by default.  Additionally, hedged reads may
       be  explicitly  enabled  or  disabled by calling mongoc_read_prefs_set_hedge() with a BSON
       document, e.g.

          {
             enabled: true
          }

       Appropriate values for the enabled key are true or false.

   mongoc_remove_flags_t
       Flags for deletion operations

   Synopsis
          typedef enum {
             MONGOC_REMOVE_NONE = 0,
             MONGOC_REMOVE_SINGLE_REMOVE = 1 << 0,
          } mongoc_remove_flags_t;

   Description
       These flags correspond to the MongoDB wire protocol. They may be  bitwise  or'd  together.
       They may change the number of documents that are removed during a remove command.

   Flag Values
                    ┌────────────────────────────┬──────────────────────────────────┐
                    │MONGOC_REMOVE_NONE          │ Specify  no  removal  flags. All │
                    │                            │ matching   documents   will   be │
                    │                            │ removed.                         │
                    ├────────────────────────────┼──────────────────────────────────┤
                    │MONGOC_REMOVE_SINGLE_REMOVE │ Only  remove  the first matching │
                    │                            │ document from the selector.      │
                    └────────────────────────────┴──────────────────────────────────┘

   mongoc_reply_flags_t
       Flags from server replies

   Synopsis
          typedef enum {
             MONGOC_REPLY_NONE = 0,
             MONGOC_REPLY_CURSOR_NOT_FOUND = 1 << 0,
             MONGOC_REPLY_QUERY_FAILURE = 1 << 1,
             MONGOC_REPLY_SHARD_CONFIG_STALE = 1 << 2,
             MONGOC_REPLY_AWAIT_CAPABLE = 1 << 3,
          } mongoc_reply_flags_t;

   Description
       These flags correspond to the wire protocol. They may be bitwise or'd together.

   Flag Values
                  ─────────────────────────────────────────────────────────────────────
                   MONGOC_REPLY_NONE                 No flags set.
                  ─────────────────────────────────────────────────────────────────────
                   MONGOC_REPLY_CURSOR_NOT_FOUND     No matching cursor was found  on
                                                     the server.
                  ─────────────────────────────────────────────────────────────────────
                   MONGOC_REPLY_QUERY_FAILURE        The query failed or was invalid.
                                                     Error    document    has    been
                                                     provided.
                  ─────────────────────────────────────────────────────────────────────
                   MONGOC_REPLY_SHARD_CONFIG_STALE   Shard config is stale.
                  ─────────────────────────────────────────────────────────────────────
                   MONGOC_REPLY_AWAIT_CAPABLE        If   the   returned   cursor  is
                                                     capable                       of
                                                     MONGOC_QUERY_AWAIT_DATA.
                  ┌────────────────────────────────┬──────────────────────────────────┐
                  │                                │                                  │
--

AUTHOR

       MongoDB, Inc

COPYRIGHT

       2017-present, MongoDB, Inc