---
name: "mongoc_reference"
section: "3"
platform: "linux"
package: "libmongoc-doc"
version: "1.30.4-1+deb13u3"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/mongoc_reference"
---

# mongoc\_reference(3)

## LIBMONGOC - API

A Cross Platform MongoDB Client Library for C

This site documents the API. For tutorials, guides, and explainers, see *MongoDB C Driver*.

### 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.

### 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

The MongoDB C driver has two different types of logging available:

- •

  The original **mongoc\_log** facility supports freeform string messages that originate from the driver itself or from application code. This has been retroactively termed "unstructured logging".

- •

  A new **mongoc\_structured\_log** facility reports messages from the driver itself using a BSON format defined across driver implementations by the *MongoDB Logging Specification*.

These two systems are configured and used independently.

### Unstructured Logging

This is the original logging facility that supports freeform string messages originating from the driver itself or from application code. This has been retroactively termed "unstructured logging". See *Structured Logging* for the newer standardized logging facility.

```
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,
            ...);
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);
```

This abstraction can be used for logging in your application, or you can integrate the driver 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.

### Structured Logging

This document describes a newer "structured" logging facility which reports messages from the driver itself using a BSON format defined across driver implementations by the *MongoDB Logging Specification*. See *Unstructured Logging* for the original freeform logging facility.

These two systems are configured and used independently.

Unstructured logging is global to the entire process, but structured logging is configured separately for each *mongoc\_client\_t* or *mongoc\_client\_pool\_t*. See *mongoc\_client\_set\_structured\_log\_opts()* and *mongoc\_client\_pool\_set\_structured\_log\_opts()*.

### Options

Structured log settings are tracked explicitly by a *mongoc\_structured\_log\_opts\_t* instance.

Like other drivers supporting structured logging, we take default settings from environment variables and offer additional optional programmatic configuration. Environment variables are captured during *mongoc\_structured\_log\_opts\_new()*, refer there for a full list of the supported variables.

Normally environment variables provide defaults that can be overridden programmatically. To request the opposite behavior, where your programmatic defaults can be overridden by the environment, see *mongoc\_structured\_log\_opts\_set\_max\_levels\_from\_env()*.

Structured log messages may be filtered in arbitrary ways by the handler, but as both a performance optimization and a convenience, a built-in filter limits the maximum log level of reported messages with a per-component setting.

### mongoc\_structured\_log\_opts\_t

### Synopsis

```
typedef struct mongoc_structured_log_opts_t mongoc_structured_log_opts_t;
```

**mongoc\_structured\_log\_opts\_t** is an opaque type that contains options for the structured logging subsystem: per-component log levels, a maximum logged document length, and a handler function.

Create a **mongoc\_structured\_log\_opts\_t** with *mongoc\_structured\_log\_opts\_new()*, set options and a callback on it, then pass it to *mongoc\_client\_set\_structured\_log\_opts()* or *mongoc\_client\_pool\_set\_structured\_log\_opts()*. Must be destroyed by calling *mongoc\_structured\_log\_opts\_destroy()*.

### Functions

### mongoc\_structured\_log\_opts\_new()

### Synopsis

```
mongoc_structured_log_opts_t *
mongoc_structured_log_opts_new (void);
```

Creates a new *mongoc\_structured\_log\_opts\_t*, filled with defaults captured from the current environment.

Sets a default log handler which would write a text representation of each log message to **stderr**, **stdout**, or another file configurable using **MONGODB\_LOG\_PATH**. This setting has no effect if the default handler is replaced using *mongoc\_structured\_log\_opts\_set\_handler()*.

Environment variable errors are non-fatal, and result in one-time warnings delivered as an unstructured log.

Per-component maximum levels are initialized equivalently to:

```
mongoc_structured_log_opts_set_max_level_for_all_components(opts, MONGOC_STRUCTURED_LOG_LEVEL_WARNING);
mongoc_structured_log_opts_set_max_levels_from_env(opts);
```

### Environment Variables

This is a full list of the captured environment variables.

- •

  **MONGODB\_LOG\_MAX\_DOCUMENT\_LENGTH**: Maximum length for JSON-serialized documents that appear within a log message. It may be a number, in bytes, or **unlimited** (case insensitive) to choose an implementation-specific value near the maximum representable length. By default, the limit is 1000 bytes. This limit affects interior documents like commands and replies, not the total length of a structured log message.

- •

  **MONGODB\_LOG\_PATH**: A file path or one of the special strings **stderr** or **stdout** (case insensitive) specifying the destination for structured logs seen by the default handler. By default, it writes to **stderr**. This path will be captured during **mongoc\_structured\_log\_opts\_new()**, but it will not immediately be opened. If the file can't be opened, a warning is then written to the unstructured log and the handler writes structured logs to **stderr** instead.

  **WARNING:**

  When a file path is given for **MONGODB\_LOG\_PATH**, each log instance (one stand-alone client or pool) will separately open this file for append. The results are operating system specific. On UNIX-like platforms each instance's output will be interleaved, in most cases without splitting individual log messages. Notably on Windows the file will be opened in exclusive mode by the first instance and subsequent instances will fail, falling back on the default of **stderr**. Applications that use multiple processes or multiple client pools will likely want to supply a log handler that annotates each message with information about its originating log instance.

- •

  **MONGODB\_LOG\_COMMAND**: A log level name to set as the maximum for **MONGOC\_STRUCTURED\_LOG\_COMPONENT\_COMMAND**.

- •

  **MONGODB\_LOG\_TOPOLOGY**: A log level name to set as the maximum for **MONGOC\_STRUCTURED\_LOG\_COMPONENT\_TOPOLOGY**.

- •

  **MONGODB\_LOG\_SERVER\_SELECTION**: A log level name to set as the maximum for **MONGOC\_STRUCTURED\_LOG\_COMPONENT\_SERVER\_SELECTION**.

- •

  **MONGODB\_LOG\_CONNECTION**: A log level name to set as the maximum for **MONGOC\_STRUCTURED\_LOG\_COMPONENT\_CONNECTION**.

- •

  **MONGODB\_LOG\_ALL**: A log level name applied to all components not otherwise specified.

Note that log level names are always case insensitive. This is a full list of recognized names, including allowed aliases:

- •

  **emergency**, **off**

- •

  **alert**

- •

  **critical**

- •

  **error**

- •

  **warning**, **warn**

- •

  **notice**

- •

  **informational**, **info**

- •

  **debug**

- •

  **trace**

### Returns

A newly allocated *mongoc\_structured\_log\_opts\_t*.

### mongoc\_structured\_log\_opts\_destroy()

### Synopsis

```
void
mongoc_structured_log_opts_destroy (mongoc_structured_log_opts_t *opts);
```

### Parameters

- •

  **opts**: Pointer to a *mongoc\_structured\_log\_opts\_t* allocated with *mongoc\_structured\_log\_opts\_new()*, or NULL.

### Description

This function releases all resources associated with a *mongoc\_structured\_log\_opts\_t*. Does nothing if **opts** is NULL.

### mongoc\_structured\_log\_opts\_set\_handler()

### Synopsis

```
void
mongoc_structured_log_opts_set_handler (mongoc_structured_log_opts_t *opts,
                                        mongoc_structured_log_func_t log_func,
                                        void *user_data);
```

Sets the function to be called to handle structured log messages, as a *mongoc\_structured\_log\_func\_t*.

The callback is given a *mongoc\_structured\_log\_entry\_t* as a handle for obtaining additional information about the log message. This entry pointer is only valid during a callback, because it's a low cost reference to temporary data.

Structured log handlers must be thread-safe if they will be used with *mongoc\_client\_pool\_t*. Handlers must avoid unbounded recursion, preferably by avoiding the use of any **libmongoc** client or pool which uses the same handler.

This function always replaces the default log handler from *mongoc\_structured\_log\_opts\_new()*, if it was still set. If the **log\_func** is set to NULL, structured logging will be disabled.

### Parameters

- •

  **opts**: Structured log options, allocated with *mongoc\_structured\_log\_opts\_new()*.

- •

  **log\_func**: The handler to install, a *mongoc\_structured\_log\_func\_t*, or NULL to disable structured logging.

- •

  **user\_data**: Optional user data, passed on to the handler.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_opts\_set\_max\_level\_for\_component()

### Synopsis

```
bool
mongoc_structured_log_opts_set_max_level_for_component (mongoc_structured_log_opts_t *opts,
                                                        mongoc_structured_log_component_t component,
                                                        mongoc_structured_log_level_t level);
```

Sets the maximum log level per-component. Only log messages at or below this severity level will be passed to *mongoc\_structured\_log\_func\_t*.

By default, each component's log level may come from environment variables. See *mongoc\_structured\_log\_opts\_set\_max\_levels\_from\_env()*.

### Parameters

- •

  **opts**: Structured log options, allocated with *mongoc\_structured\_log\_opts\_new()*.

- •

  **component**: The component to set a max log level. for, as a *mongoc\_structured\_log\_component\_t*.

- •

  **level**: The new max log level for this component, as a *mongoc\_structured\_log\_level\_t*.

### Returns

Returns **true** on success, or **false** if the supplied parameters were incorrect.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_opts\_set\_max\_level\_for\_all\_components()

### Synopsis

```
bool
mongoc_structured_log_opts_set_max_level_for_all_components (mongoc_structured_log_opts_t *opts,
                                                             mongoc_structured_log_level_t level);
```

Sets all per-component maximum log levels to the same value. Only log messages at or below this severity level will be passed to *mongoc\_structured\_log\_func\_t*. Effective even for logging components not known at compile-time.

### Parameters

- •

  **opts**: Structured log options, allocated with *mongoc\_structured\_log\_opts\_new()*.

- •

  **level**: The max log level for all components, as a *mongoc\_structured\_log\_level\_t*.

### Returns

Returns **true** on success, or **false** if the supplied parameters were incorrect.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_opts\_set\_max\_levels\_from\_env()

### Synopsis

```
bool
mongoc_structured_log_opts_set_max_levels_from_env (mongoc_structured_log_opts_t *opts);
```

Sets any maximum log levels requested by environment variables: **MONGODB\_LOG\_ALL** for all components, followed by per-component log levels **MONGODB\_LOG\_COMMAND**, **MONGODB\_LOG\_CONNECTION**, **MONGODB\_LOG\_TOPOLOGY**, and **MONGODB\_LOG\_SERVER\_SELECTION**.

Expects the value to be recognizable by *mongoc\_structured\_log\_get\_named\_level()*. Parse errors may cause a warning message, delivered via unstructured logging.

Component levels with no valid environment variable setting will be left unmodified.

This happens automatically when *mongoc\_structured\_log\_opts\_new()* establishes defaults. Any subsequent programmatic modifications to the *mongoc\_structured\_log\_opts\_t* will override the environment variable settings. For applications that desire the opposite behavior, where environment variables may override programmatic settings, they may call **mongoc\_structured\_log\_opts\_set\_max\_levels\_from\_env()** after calling *mongoc\_structured\_log\_opts\_set\_max\_level\_for\_component()* and *mongoc\_structured\_log\_opts\_set\_max\_level\_for\_all\_components()*. This will process the environment a second time, allowing it to override customized defaults.

### Returns

Returns **true** on success. If warnings are encountered in the environment, returns **false** and may log additional information to the unstructured logging facility. Note that, by design, these errors are by default non-fatal. When *mongoc\_structured\_log\_opts\_new()* internally calls this function, it ignores the return value.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_opts\_get\_max\_level\_for\_component()

### Synopsis

```
mongoc_structured_log_level_t
mongoc_structured_log_opts_get_max_level_for_component (const mongoc_structured_log_opts_t *opts,
                                                        mongoc_structured_log_component_t component);
```

### Parameters

- •

  **opts**: Structured log options, allocated with *mongoc\_structured\_log\_opts\_new()*.

- •

  **component**: Log component as a *mongoc\_structured\_log\_component\_t*.

### Returns

Returns the configured maximum log level for a specific component, as a *mongoc\_structured\_log\_level\_t*. This may be the last value set with *mongoc\_structured\_log\_opts\_set\_max\_level\_for\_component()* or *mongoc\_structured\_log\_opts\_set\_max\_level\_for\_all\_components()*, or it may be the default obtained from environment variables. If an invalid or unknown component enum is given, returns the lowest log level.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_opts\_set\_max\_document\_length()

### Synopsis

```
bool
mongoc_structured_log_opts_set_max_document_length (mongoc_structured_log_opts_t *opts,
                                                    size_t max_document_length);
```

Sets a maximum length for BSON documents that appear serialized in JSON form as part of a structured log message.

Serialized JSON will be truncated at this limit, interpreted as a count of UTF-8 encoded bytes. Truncation will be indicated with a **...** suffix, the length of which is not included in the max document length. If truncation at the exact indicated length would split a valid UTF-8 sequence, we instead truncate the document earlier at the nearest boundary between code points.

### Parameters

- •

  **opts**: Structured log options, allocated with *mongoc\_structured\_log\_opts\_new()*.

- •

  **max\_document\_length**: Maximum length for each embedded JSON document, in bytes, not including an ellipsis (**...**) added to indicate truncation. Values near or above **INT\_MAX** will be rejected.

### Returns

Returns **true** on success, or **false** if the supplied maximum length is too large.

**SEE ALSO:**

```
Structured Logging
mongoc_structured_log_opts_set_max_document_length_from_env()
```

### mongoc\_structured\_log\_opts\_set\_max\_document\_length\_from\_env()

### Synopsis

```
bool
mongoc_structured_log_opts_set_max_document_length_from_env (mongoc_structured_log_opts_t *opts);
```

Sets a maximum document length from the **MONGODB\_LOG\_MAX\_DOCUMENT\_LENGTH** environment variable, if a valid setting is found. See *mongoc\_structured\_log\_opts\_new()* for a description of the supported environment variable formats.

Parse errors may cause a warning message, delivered via unstructured logging.

This happens automatically when *mongoc\_structured\_log\_opts\_new()* establishes defaults. Any subsequent programmatic modifications to the *mongoc\_structured\_log\_opts\_t* will override the environment variable settings. For applications that desire the opposite behavior, where environment variables may override programmatic settings, they may call **mongoc\_structured\_log\_opts\_set\_max\_document\_length\_from\_env()** after calling *mongoc\_structured\_log\_opts\_set\_max\_document\_length()*. This will process the environment a second time, allowing it to override customized defaults.

### Returns

Returns **true** on success: either a valid environment setting was found, or the value is unset and **opts** will not be modified. If warnings are encountered in the environment, returns **false** and may log additional information to the unstructured logging facility. Note that, by design, these errors are by default non-fatal. When *mongoc\_structured\_log\_opts\_new()* internally calls this function, it ignores the return value.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_opts\_get\_max\_document\_length()

### Synopsis

```
size_t
mongoc_structured_log_opts_get_max_document_length (const mongoc_structured_log_opts_t *opts);
```

### Parameters

- •

  **opts**: Structured log options, allocated with *mongoc\_structured\_log\_opts\_new()*.

### Returns

Returns the current maximum document length set in **opts**, as a **size\_t**.

**SEE ALSO:**

```
Structured Logging
```

**SEE ALSO:**

```
Structured Logging
```

### Levels and Components

Log levels and components are defined as *mongoc\_structured\_log\_level\_t* and *mongoc\_structured\_log\_component\_t* enumerations. Utilities are provided to convert between these values and their standard string representations. The string values are case-insensitive.

```
typedef enum {
  MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY = 0,  // "Emergency" ("off" also accepted)
  MONGOC_STRUCTURED_LOG_LEVEL_ALERT = 1,      // "Alert"
  MONGOC_STRUCTURED_LOG_LEVEL_CRITICAL = 2,   // "Critical"
  MONGOC_STRUCTURED_LOG_LEVEL_ERROR = 3,      // "Error"
  MONGOC_STRUCTURED_LOG_LEVEL_WARNING = 4,    // "Warning" ("warn" also accepted)
  MONGOC_STRUCTURED_LOG_LEVEL_NOTICE = 5,     // "Notice"
  MONGOC_STRUCTURED_LOG_LEVEL_INFO = 6,       // "Informational" ("info" also accepted)
  MONGOC_STRUCTURED_LOG_LEVEL_DEBUG = 7,      // "Debug"
  MONGOC_STRUCTURED_LOG_LEVEL_TRACE = 8,      // "Trace"
} mongoc_structured_log_level_t;
typedef enum {
  MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND = 0,           // "command"
  MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY = 1,          // "topology"
  MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION = 2,  // "serverSelection"
  MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION = 3,        // "connection"
} mongoc_structured_log_component_t;
```

### mongoc\_structured\_log\_level\_t

### Synopsis

```
typedef enum {
   MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY = 0,
   MONGOC_STRUCTURED_LOG_LEVEL_ALERT = 1,
   MONGOC_STRUCTURED_LOG_LEVEL_CRITICAL = 2,
   MONGOC_STRUCTURED_LOG_LEVEL_ERROR = 3,
   MONGOC_STRUCTURED_LOG_LEVEL_WARNING = 4,
   MONGOC_STRUCTURED_LOG_LEVEL_NOTICE = 5,
   MONGOC_STRUCTURED_LOG_LEVEL_INFO = 6,
   MONGOC_STRUCTURED_LOG_LEVEL_DEBUG = 7,
   MONGOC_STRUCTURED_LOG_LEVEL_TRACE = 8,
} mongoc_structured_log_level_t;
```

**mongoc\_structured\_log\_level\_t** enumerates the available log levels for use with structured logging.

### Functions

### mongoc\_structured\_log\_get\_level\_name()

### Synopsis

```
const char *
mongoc_structured_log_get_level_name (mongoc_structured_log_level_t level);
```

### Parameters

- •

  **level**: Log level as a *mongoc\_structured\_log\_level\_t*.

### Returns

If the level is known, returns a pointer to a constant string that should not be freed. If the level has no known name, returns NULL.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_get\_named\_level()

### Synopsis

```
bool
mongoc_structured_log_get_named_level (const char *name, mongoc_structured_log_level_t *out);
```

Look up a log level by name. Case insensitive.

### Parameters

- •

  **name**: A name to look up as a log level.

- •

  **out**: On success, the corresponding *mongoc\_structured\_log\_level\_t* is written here.

### Returns

If the level name is known, returns **true** and writes the level enum to **\*out**. If the level name is not known, returns **false** and does not write **\*out**.

**SEE ALSO:**

```
Structured Logging
```

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_component\_t

### Synopsis

```
typedef enum {
   MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND = 0,
   MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY = 1,
   MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION = 2,
   MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION = 3,
} mongoc_structured_log_component_t;
```

**mongoc\_structured\_log\_component\_t** enumerates the structured logging components. Applications should never rely on having an exhaustive list of all log components. Instead, use *mongoc\_structured\_log\_opts\_set\_max\_level\_for\_all\_components()* to set a default level if needed.

### Functions

### mongoc\_structured\_log\_get\_component\_name()

### Synopsis

```
const char *
mongoc_structured_log_get_component_name (mongoc_structured_log_component_t component);
```

### Parameters

- •

  **component**: Log component as a *mongoc\_structured\_log\_component\_t*.

### Returns

If the component is known, returns a pointer to a constant string that should not be freed. If the component has no known name, returns NULL.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_get\_named\_component()

### Synopsis

```
bool
mongoc_structured_log_get_named_component (const char *name, mongoc_structured_log_component_t *out);
```

Look up a component by name. Case insensitive.

### Parameters

- •

  **name**: A name to look up as a log component.

- •

  **out**: On success, the corresponding *mongoc\_structured\_log\_component\_t* is written here.

### Returns

If the component name is known, returns **true** and writes the component enum to **\*out**. If the component name is not known, returns **false** and does not write **\*out**.

**SEE ALSO:**

```
Structured Logging
```

**SEE ALSO:**

```
Structured Logging
```

**SEE ALSO:**

mongoc\_structured\_log\_get\_level\_name mongoc\_structured\_log\_get\_named\_level mongoc\_structured\_log\_get\_component\_name mongoc\_structured\_log\_get\_named\_component

### Log Handlers

Each *mongoc\_client\_pool\_t* or standalone *mongoc\_client\_t* has its own instance of the structured logging subsystem, with its own settings and handler.

When using *mongoc\_client\_pool\_t*, the pooled clients all share a common logging instance. Handlers must be thread-safe.

The handler is called for each log entry with a level no greater than its component's maximum. A *mongoc\_structured\_log\_entry\_t* pointer provides access to further details, during the handler only.

Handlers must take care not to re-enter **libmongoc** with the same *mongoc\_client\_t* or *mongoc\_client\_pool\_t* that the handler has been called by.

### mongoc\_structured\_log\_func\_t

### Synopsis

```
typedef void (*mongoc_structured_log_func_t)
(const mongoc_structured_log_entry_t *entry, void *user_data);
```

Callback function for *mongoc\_structured\_log\_opts\_set\_handler()*. Structured log handlers must be thread-safe if they will be used with *mongoc\_client\_pool\_t*. Handlers must avoid unbounded recursion, preferably by avoiding the use of any **libmongoc** client or pool which uses the same handler.

### Parameters

- •

  **entry**: A *mongoc\_structured\_log\_entry\_t* pointer, only valid during the handler invocation.

- •

  **user\_data**: Optional user data from *mongoc\_structured\_log\_opts\_set\_handler()*.

**SEE ALSO:**

```
Structured Logging
```

### Log Entries

Each log entry is represented within the handler by a short-lived *mongoc\_structured\_log\_entry\_t* pointer. During the handler, this pointer can be used to access the individual properties of an entry: its level, component, and message.

The message will be assembled as a *bson\_t* only when explicitly requested by a call to *mongoc\_structured\_log\_entry\_message\_as\_bson()*. This results in a standalone document that may be retained for any amount of time and must be explicitly destroyed.

### mongoc\_structured\_log\_entry\_t

### Synopsis

```
typedef struct mongoc_structured_log_entry_t mongoc_structured_log_entry_t;
```

**mongoc\_structured\_log\_entry\_t** is an opaque structure which represents the temporary state of an in-progress log entry. It can only be used during a *mongoc\_structured\_log\_func\_t*, it is not valid after the log handler returns. Use the functions below to query individual aspects of the log entry.

### Functions

### mongoc\_structured\_log\_entry\_get\_component()

### Synopsis

```
mongoc_structured_log_component_t
mongoc_structured_log_entry_get_component (const mongoc_structured_log_entry_t *entry);
```

### Parameters

- •

  **entry**: A *mongoc\_structured\_log\_entry\_t* pointer.

### Returns

The *mongoc\_structured\_log\_component\_t* associated with this log entry.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_entry\_get\_level()

### Synopsis

```
mongoc_structured_log_level_t
mongoc_structured_log_entry_get_level (const mongoc_structured_log_entry_t *entry);
```

### Parameters

- •

  **entry**: A *mongoc\_structured\_log\_entry\_t* pointer.

### Returns

The *mongoc\_structured\_log\_level\_t* associated with this log entry.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_entry\_get\_message\_string()

### Synopsis

```
const char *
mongoc_structured_log_entry_get_message_string (const mongoc_structured_log_entry_t *entry);
```

### Parameters

- •

  **entry**: A *mongoc\_structured\_log\_entry\_t* pointer.

### Returns

A string, guaranteed to be valid only during the lifetime of the structured log handler. It should not be freed or modified.

Identical to the value of the **message** key in the document returned by *mongoc\_structured\_log\_entry\_message\_as\_bson()*.

This is not a complete string representation of the structured log, but rather a standardized identifier for a particular log event.

**SEE ALSO:**

```
Structured Logging
```

### mongoc\_structured\_log\_entry\_message\_as\_bson()

### Synopsis

```
bson_t *
mongoc_structured_log_entry_message_as_bson (const mongoc_structured_log_entry_t *entry);
```

Make a new copy, as a *bson\_t*, of the log entry's standardized BSON representation. When possible, a log handler should avoid serializing log messages that will be discarded. Each call allocates an independent copy of the message that must be freed.

### Parameters

- •

  **entry**: A *mongoc\_structured\_log\_entry\_t* pointer.

### Returns

A new allocated *bson\_t* that must be freed with a call to *bson\_destroy()*.

**SEE ALSO:**

```
Structured Logging
```

**SEE ALSO:**

```
Structured Logging
```

### Example

example-structured-log.c

```
/* gcc example-structured-log.c -o example-structured-log \
 *     $(pkg-config --cflags --libs libmongoc-1.0) */
#include <mongoc/mongoc.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
static pthread_mutex_t handler_mutex;
static void
example_handler (const mongoc_structured_log_entry_t *entry, void *user_data)
{
   mongoc_structured_log_component_t component = mongoc_structured_log_entry_get_component (entry);
   mongoc_structured_log_level_t level = mongoc_structured_log_entry_get_level (entry);
   const char *message_string = mongoc_structured_log_entry_get_message_string (entry);
   /*
    * With a single-threaded mongoc_client_t, handlers will always be called
    * by the thread that owns the client. On a mongoc_client_pool_t, handlers
    * are shared by multiple threads and must be reentrant.
    *
    * Note that unstructured logging includes a global mutex in the API,
    * but structured logging allows applications to avoid lock contention
    * even when multiple threads are issuing commands simultaneously.
    *
    * Simple apps like this example can achieve thread safety by adding their
    * own global mutex. For other apps, this would be a performance bottleneck
    * and it would be more appropriate for handlers to process their log
    * messages concurrently.
    *
    * In this example, our mutex protects access to a global log counter.
    * In a real application, you may need to protect access to a shared stream
    * or queue.
    */
   pthread_mutex_lock (&handler_mutex);
   static unsigned log_serial_number = 0;
   printf ("%u. Log entry with component=%s level=%s message_string='%s'\n",
           ++log_serial_number,
           mongoc_structured_log_get_component_name (component),
           mongoc_structured_log_get_level_name (level),
           message_string);
   /*
    * At this point, the handler might make additional filtering decisions
    * before asking for a bson_t. As an example, let's log the component and
    * level for all messages but only show contents for command logs.
    */
   if (component == MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND) {
      bson_t *message = mongoc_structured_log_entry_message_as_bson (entry);
      char *json = bson_as_relaxed_extended_json (message, NULL);
      printf ("Full log message, as json: %s\n", json);
      bson_destroy (message);
      bson_free (json);
   }
   pthread_mutex_unlock (&handler_mutex);
}
int
main (void)
{
   const char *uri_string = "mongodb://localhost:27017";
   int result = EXIT_FAILURE;
   bson_error_t error;
   mongoc_uri_t *uri = NULL;
   mongoc_structured_log_opts_t *log_opts = NULL;
   mongoc_client_t *client = NULL;
   mongoc_client_pool_t *pool = NULL;
   /*
    * Note that structured logging only applies per-client or per-pool,
    * and it won't be used during or before mongoc_init.
    */
   mongoc_init ();
   /*
    * Logging options are represented by a mongoc_structured_log_opts_t,
    * which can be copied into a mongoc_client_t or mongoc_client_pool_t
    * using mongoc_client_set_structured_log_opts() or
    * mongoc_client_pool_set_structured_log_opts(), respectively.
    *
    * Default settings are captured from the environment into
    * this structure when it's constructed.
    */
   log_opts = mongoc_structured_log_opts_new ();
   /*
    * For demonstration purposes, set up a handler that receives all possible log messages.
    */
   pthread_mutex_init (&handler_mutex, NULL);
   mongoc_structured_log_opts_set_max_level_for_all_components (log_opts, MONGOC_STRUCTURED_LOG_LEVEL_TRACE);
   mongoc_structured_log_opts_set_handler (log_opts, example_handler, NULL);
   /*
    * By default libmongoc proceses log options from the environment first,
    * and then allows you to apply programmatic overrides. To request the
    * opposite behavior, allowing the environment to override programmatic
    * defaults, you can ask for the environment to be re-read after setting
    * your own defaults.
    */
   mongoc_structured_log_opts_set_max_levels_from_env (log_opts);
   /*
    * Create a MongoDB URI object. This example assumes a local server.
    */
   uri = mongoc_uri_new_with_error (uri_string, &error);
   if (!uri) {
      fprintf (stderr, "URI parse error: %s\n", error.message);
      goto done;
   }
   /*
    * Create a new client pool.
    */
   pool = mongoc_client_pool_new (uri);
   if (!pool) {
      goto done;
   }
   /*
    * Set the client pool's log options.
    * This must happen only once, and only before the first mongoc_client_pool_pop.
    * There's no need to keep log_opts after this point.
    */
   mongoc_client_pool_set_structured_log_opts (pool, log_opts);
   /*
    * Check out a client, and do some work that we'll see logs from.
    * This example just sends a 'ping' command.
    */
   client = mongoc_client_pool_pop (pool);
   if (!client) {
      goto done;
   }
   bson_t *command = BCON_NEW ("ping", BCON_INT32 (1));
   bson_t reply;
   bool command_ret = mongoc_client_command_simple (client, "admin", command, NULL, &reply, &error);
   bson_destroy (command);
   bson_destroy (&reply);
   mongoc_client_pool_push (pool, client);
   if (!command_ret) {
      fprintf (stderr, "Command error: %s\n", error.message);
      goto done;
   }
   result = EXIT_SUCCESS;
done:
   mongoc_uri_destroy (uri);
   mongoc_structured_log_opts_destroy (log_opts);
   mongoc_client_pool_destroy (pool);
   mongoc_cleanup ();
   return result;
}
```

**SEE ALSO:**

mongoc\_structured\_log\_entry\_get\_component mongoc\_structured\_log\_entry\_get\_level mongoc\_structured\_log\_entry\_message\_as\_bson

« *libmongoc - API*

### 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.
```

| | | |
| --- | --- | --- |
| Code | Description |  |
| **MONGOC\_ERROR\_CLIENT** | **MONGOC\_ERROR\_CLIENT\_TOO\_BIG** | You tried to send a message larger than the server's max message size. |
|  | **MONGOC\_ERROR\_CLIENT\_AUTHENTICATE** | Wrong credentials, or failure sending or receiving authentication messages. |
|  | **MONGOC\_ERROR\_CLIENT\_NO\_ACCEPTABLE\_PEER** | You tried an TLS connection but the driver was not built with TLS. |
|  | **MONGOC\_ERROR\_CLIENT\_IN\_EXHAUST** | You began iterating an exhaust cursor, then tried to begin another operation with the same *mongoc\_client\_t*. |
|  | **MONGOC\_ERROR\_CLIENT\_SESSION\_FAILURE** | Failure related to creating or using a logical session. |
|  | **MONGOC\_ERROR\_CLIENT\_INVALID\_ENCRYPTION\_ARG** | Failure related to arguments passed when initializing In-Use Encryption. |
|  | **MONGOC\_ERROR\_CLIENT\_INVALID\_ENCRYPTION\_STATE** | Failure related to In-Use Encryption. |
|  | **MONGOC\_ERROR\_CLIENT\_INVALID\_LOAD\_BALANCER** | You attempted to connect to a MongoDB server behind a load balancer, but the server does not advertize load balanced support. |
| **MONGOC\_ERROR\_STREAM** | **MONGOC\_ERROR\_STREAM\_NAME\_RESOLUTION** | DNS failure. |
|  | **MONGOC\_ERROR\_STREAM\_SOCKET** | Timeout communicating with server, or connection closed. |
|  | **MONGOC\_ERROR\_STREAM\_CONNECT** | Failed to connect to server. |
| **MONGOC\_ERROR\_PROTOCOL** | **MONGOC\_ERROR\_PROTOCOL\_INVALID\_REPLY** | Corrupt response from server. |
|  | **MONGOC\_ERROR\_PROTOCOL\_BAD\_WIRE\_VERSION** | The server version is too old or too new to communicate with the driver. |
| **MONGOC\_ERROR\_CURSOR** | **MONGOC\_ERROR\_CURSOR\_INVALID\_CURSOR** | You passed bad arguments to *mongoc\_collection\_find\_with\_opts()*, or you called *mongoc\_cursor\_next()* on a completed or failed cursor, or the cursor timed out on the server. |
|  | **MONGOC\_ERROR\_CHANGE\_STREAM\_NO\_RESUME\_TOKEN** | A resume token was not returned in a document found with *mongoc\_change\_stream\_next()* |
| **MONGOC\_ERROR\_QUERY** | **MONGOC\_ERROR\_QUERY\_FAILURE** | *Error API Version 1*: Server error from command or query. The server error message is in **message**. |
| **MONGOC\_ERROR\_SERVER** | **MONGOC\_ERROR\_QUERY\_FAILURE** | *Error API Version 2*: Server error from command or query. The server error message is in **message**. |
| **MONGOC\_ERROR\_SASL** | A SASL error code. | **man sasl\_errors** for a list of codes. |
| **MONGOC\_ERROR\_BSON** | **MONGOC\_ERROR\_BSON\_INVALID** | You passed an invalid or oversized BSON document as a parameter, or called *mongoc\_collection\_create\_index()* with invalid keys, or the server reply was corrupt. |
| **MONGOC\_ERROR\_NAMESPACE** | **MONGOC\_ERROR\_NAMESPACE\_INVALID** | You tried to create a collection with an invalid name. |
| **MONGOC\_ERROR\_COMMAND** | **MONGOC\_ERROR\_COMMAND\_INVALID\_ARG** | Many functions set this error code when passed bad parameters. Print the error message for details. |
|  | **MONGOC\_ERROR\_PROTOCOL\_BAD\_WIRE\_VERSION** | You tried to use a command option the server does not support. |
|  | **MONGOC\_ERROR\_DUPLICATE\_KEY** | An insert or update failed because because of a duplicate **\_id** or other unique-index violation. |
|  | **MONGOC\_ERROR\_MAX\_TIME\_MS\_EXPIRED** | The operation failed because maxTimeMS expired. |
|  | **MONGOC\_ERROR\_SERVER\_SELECTION\_INVALID\_ID** | The **serverId** option for an operation conflicts with the pinned server for that operation's client session (denoted by the **sessionId** option). |
| **MONGOC\_ERROR\_COMMAND** | *Error code from server*. | *Error API Version 1*: Server error from a command. The server error message is in **message**. |
| **MONGOC\_ERROR\_SERVER** | *Error code from server*. | *Error API Version 2*: Server error from a command. The server error message is in **message**. |
| **MONGOC\_ERROR\_COLLECTION** | **MONGOC\_ERROR\_COLLECTION\_INSERT\_FAILED**, **MONGOC\_ERROR\_COLLECTION\_UPDATE\_FAILED**, **MONGOC\_ERROR\_COLLECTION\_DELETE\_FAILED**. | Invalid or empty input to *mongoc\_collection\_insert\_one()*, *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\_COLLECTION** | *Error code from server*. | *Error API Version 1*: Server error from *mongoc\_collection\_insert\_one()*, *mongoc\_collection\_insert\_bulk()*, *mongoc\_collection\_update\_one()*, *mongoc\_collection\_update\_many()*, *mongoc\_collection\_replace\_one()*, |
| **MONGOC\_ERROR\_SERVER** | *Error code from server*. | *Error API Version 2*: Server error from *mongoc\_collection\_insert\_one()*, *mongoc\_collection\_insert\_bulk()*, *mongoc\_collection\_update\_one()*, *mongoc\_collection\_update\_many()*, *mongoc\_collection\_replace\_one()*, |
| **MONGOC\_ERROR\_GRIDFS** | **MONGOC\_ERROR\_GRIDFS\_CHUNK\_MISSING** | The GridFS file is missing a document in its **chunks** collection. |
|  | **MONGOC\_ERROR\_GRIDFS\_CORRUPT** | A data inconsistency was detected in GridFS. |
|  | **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 to write on a closed GridFS stream. |
|  | **MONGOC\_ERROR\_GRIDFS\_BUCKET\_FILE\_NOT\_FOUND** | A GridFS file is missing from **files** collection. |
|  | **MONGOC\_ERROR\_GRIDFS\_BUCKET\_STREAM** | An error occurred on a stream created from a GridFS operation like *mongoc\_gridfs\_bucket\_upload\_from\_stream()*. |
| **MONGOC\_ERROR\_SCRAM** | **MONGOC\_ERROR\_SCRAM\_PROTOCOL\_ERROR** | Failure in SCRAM-SHA-1 or SCRAM-SHA-256 authentication. |
| **MONGOC\_ERROR\_SERVER\_SELECTION** | **MONGOC\_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\_CONCERN** | *Error code from server*. | There was a *write concern* error or *timeout* from the server. |
| **MONGOC\_ERROR\_TRANSACTION** | **MONGOC\_ERROR\_TRANSACTION\_INVALID** | You attempted to start a transaction when one is already in progress, or commit or abort when there is no transaction. |
| **MONGOC\_ERROR\_CLIENT\_SIDE\_ENCRYPTION** | Error code produced by libmongocrypt. | An error occurred in the library responsible for In-Use Encryption |
| **MONGOC\_ERROR\_AZURE** | **MONGOC\_ERROR\_KMS\_SERVER\_HTTP** | An Azure HTTP service responded with an error status |
|  | **MONGOC\_ERROR\_KMS\_SERVER\_BAD\_JSON** | An Azure service responded with invalid JSON data |
| **MONGOC\_ERROR\_GCP** | **MONGOC\_ERROR\_KMS\_SERVER\_HTTP** | A GCP HTTP service responded with an error status |
|  | **MONGOC\_ERROR\_KMS\_SERVER\_BAD\_JSON** | A GCP service responded with invalid JSON data |

### 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.

| | | |
| --- | --- | --- |
| Error Source | API Version 1 | API Version 2 |
| *mongoc\_cursor\_error()* | **MONGOC\_ERROR\_QUERY** | **MONGOC\_ERROR\_SERVER** |
| *mongoc\_client\_command\_with\_opts()*, *mongoc\_database\_command\_with\_opts()*, and other command functions | **MONGOC\_ERROR\_QUERY** | **MONGOC\_ERROR\_SERVER** |
| *mongoc\_collection\_count\_with\_opts()* *mongoc\_client\_get\_database\_names\_with\_opts()*, and other command helper functions | **MONGOC\_ERROR\_QUERY** | **MONGOC\_ERROR\_SERVER** |
| *mongoc\_collection\_insert\_one()* *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\_ERROR\_COMMAND** | **MONGOC\_ERROR\_SERVER** |
| *mongoc\_bulk\_operation\_execute()* | **MONGOC\_ERROR\_COMMAND** | **MONGOC\_ERROR\_SERVER** |
| Write-concern timeout | **MONGOC\_ERROR\_WRITE\_CONCERN** | **MONGOC\_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\_bulkwrite\_t

### Synopsis

```
typedef struct _mongoc_bulkwrite_t mongoc_bulkwrite_t;
```

### Description

*mongoc\_bulkwrite\_t* provides an abstraction for submitting multiple write operations as a single batch.

After adding all of the write operations to the *mongoc\_bulkwrite\_t*, call *mongoc\_bulkwrite\_execute()* to execute the operation.

**WARNING:**

It is only valid to call *mongoc\_bulkwrite\_execute()* once. The *mongoc\_bulkwrite\_t* must be destroyed afterwards.

**NOTE:**

If using MongoDB server 8.0+, prefer *mongoc\_bulkwrite\_t* over *mongoc\_bulk\_operation\_t* to reduce network round trips.

*mongoc\_bulkwrite\_t* uses the **bulkWrite** server command introduced in MongoDB server 8.0. **bulkWrite** command supports insert, update, and delete operations in the same payload. **bulkWrite** supports use of multiple collection namespaces in the same payload.

*mongoc\_bulk\_operation\_t* uses the **insert**, **update** and **delete** server commands available in all current MongoDB server versions. Write operations are grouped by type (insert, update, delete) and sent in separate commands. Only one collection may be specified per bulk write.

### mongoc\_bulkwriteopts\_t

### Synopsis

```
typedef struct _mongoc_bulkwriteopts_t mongoc_bulkwriteopts_t;
```

### mongoc\_bulkwriteresult\_t

### Synopsis

```
typedef struct _mongoc_bulkwriteresult_t mongoc_bulkwriteresult_t;
```

### mongoc\_bulkwriteexception\_t

### Synopsis

```
typedef struct _mongoc_bulkwriteexception_t mongoc_bulkwriteexception_t;
```

### mongoc\_bulk\_operation\_t

Bulk Write Operations

### Synopsis

```
typedef struct _mongoc_bulk_operation_t mongoc_bulk_operation_t;
```

### Description

*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_bulkwrite_t
```

**NOTE:**

If using MongoDB server 8.0+, prefer *mongoc\_bulkwrite\_t* over *mongoc\_bulk\_operation\_t* to reduce network round trips.

*mongoc\_bulkwrite\_t* uses the **bulkWrite** server command introduced in MongoDB server 8.0. **bulkWrite** command supports insert, update, and delete operations in the same payload. **bulkWrite** supports use of multiple collection namespaces in the same payload.

*mongoc\_bulk\_operation\_t* uses the **insert**, **update** and **delete** server commands available in all current MongoDB server versions. Write operations are grouped by type (insert, update, delete) and sent in separate commands. Only one collection may be specified per bulk write.

### 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;
```

Added in version 1.24.0.

RangeOpts specifies index options for a Queryable Encryption field supporting "range" queries. Used to set options for *mongoc\_client\_encryption\_encrypt()*.

The options min, max, trim factor, 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_relaxed_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);
      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.

### Parameters

- •

  **session**: 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: Use *mongoc\_collection\_delete\_one()* or *mongoc\_collection\_delete\_many()* instead.

### 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, (int) (__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, (int) (__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, (int) (__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, (int) (__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, (int) (__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, (int) (__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, (int) (__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.

### Related

- •

  *mongoc\_client\_t*

- •

  *mongoc\_gridfs\_t*

- •

  *mongoc\_gridfs\_file\_list\_t*

- •

  *mongoc\_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: See *Manage Collection Indexes* for alternatives.

### 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 default. | 3.2 |
| 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. |

### mongoc\_server\_api\_t

A versioned API to use for connections.

### Synopsis

Used to specify which version of the MongoDB server's API to use for driver connections.

The server API type takes a *mongoc\_server\_api\_version\_t*. It can optionally be strict about the list of allowed commands in that API version, and can also optionally provide errors for deprecated commands in that API version.

A *mongoc\_server\_api\_t* can be set on a client, and will then be sent to MongoDB for most commands run using that client.

### mongoc\_server\_api\_version\_t

A representation of server API version numbers.

### Synopsis

Used to specify which version of the MongoDB server's API to use for driver connections.

### Supported API Versions

The driver currently supports the following MongoDB API versions:

| | |
| --- | --- |
| Enum value | MongoDB version string |
| MONGOC\_SERVER\_API\_V1 | "1" |

### mongoc\_server\_description\_t

Server description

### Synopsis

```
#include <mongoc/mongoc.h>
typedef struct _mongoc_server_description_t mongoc_server_description_t
```

**mongoc\_server\_description\_t** holds information about a mongod or mongos the driver is connected to.

### Lifecycle

Clean up a **mongoc\_server\_description\_t** with *mongoc\_server\_description\_destroy()* when necessary.

Applications receive a temporary reference to a **mongoc\_server\_description\_t** as a parameter to an SDAM Monitoring callback that must not be destroyed. See *Introduction to Application Performance Monitoring*.

**SEE ALSO:**

```
mongoc_client_get_server_descriptions().
```

### mongoc\_session\_opt\_t

```
#include <mongoc/mongoc.h>
typedef struct _mongoc_session_opt_t mongoc_session_opt_t;
```

### 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.

See the example code for *mongoc\_session\_opts\_set\_causal\_consistency()*.

### mongoc\_socket\_t

Portable socket abstraction

### Synopsis

```
#include <mongoc/mongoc.h>
typedef struct _mongoc_socket_t mongoc_socket_t
```

### Synopsis

This structure provides a socket abstraction that is friendlier for portability than BSD sockets directly. Inconsistencies between Linux, various BSDs, Solaris, and Windows are handled here.

### mongoc\_ssl\_opt\_t

### Synopsis

```
typedef struct {
   const char *pem_file;
   const char *pem_pwd;
   const char *ca_file;
   const char *ca_dir;
   const char *crl_file;
   bool weak_cert_validation;
   bool allow_invalid_hostname;
   void *internal;
   void *padding[6];
} mongoc_ssl_opt_t;
```

**NOTE:**

Though some API names include the term "ssl", the C driver only support TLS protocols, which supersede SSL.

### Description

This structure is used to set the TLS options for a *mongoc\_client\_t* or *mongoc\_client\_pool\_t*.

Beginning in version 1.2.0, once a pool or client has any TLS options set, all connections use TLS, even if **ssl=true** is omitted from the MongoDB URI. Before, TLS options were ignored unless **tls=true** was included in the URI.

As of 1.4.0, the *mongoc\_client\_pool\_set\_ssl\_opts()* and *mongoc\_client\_set\_ssl\_opts()* will not only shallow copy the struct, but will also copy the **const char\***. It is therefore no longer needed to make sure the values remain valid after setting them.

**SEE ALSO:**

```
Configuring TLS
```

```
mongoc_client_set_ssl_opts()
```

```
mongoc_client_pool_set_ssl_opts()
```

### mongoc\_stream\_buffered\_t

### Synopsis

```
typedef struct _mongoc_stream_buffered_t mongoc_stream_buffered_t;
```

### Description

**mongoc\_stream\_buffered\_t** should be considered a subclass of *mongoc\_stream\_t*. It performs buffering on an underlying stream.

**SEE ALSO:**

```
mongoc_stream_buffered_new()
```

```
mongoc_stream_destroy()
```

### mongoc\_stream\_file\_t

### Synopsis

```
typedef struct _mongoc_stream_file_t mongoc_stream_file_t
```

**mongoc\_stream\_file\_t** is a *mongoc\_stream\_t* subclass for working with standard UNIX style file-descriptors.

### mongoc\_stream\_socket\_t

### Synopsis

```
typedef struct _mongoc_stream_socket_t mongoc_stream_socket_t
```

**mongoc\_stream\_socket\_t** should be considered a subclass of *mongoc\_stream\_t* that works upon socket streams.

### mongoc\_stream\_t

### Synopsis

```
typedef struct _mongoc_stream_t mongoc_stream_t
```

**mongoc\_stream\_t** provides a generic streaming IO abstraction based on a struct of pointers interface. The idea is to allow wrappers, perhaps other language drivers, to easily shim their IO system on top of **mongoc\_stream\_t**.

The API for the stream abstraction is currently private and non-extensible.

### Stream Types

There are a number of built in stream types that come with mongoc. The default configuration is a buffered unix stream. If TLS is in use, that in turn is wrapped in a tls stream.

**SEE ALSO:**

```
mongoc_stream_buffered_t
```

```
mongoc_stream_file_t
```

```
mongoc_stream_socket_t
```

```
mongoc_stream_tls_t
```

### mongoc\_stream\_tls\_t

### Synopsis

```
typedef struct _mongoc_stream_tls_t mongoc_stream_tls_t
```

**mongoc\_stream\_tls\_t** is a *mongoc\_stream\_t* subclass for working with TLS streams.

### mongoc\_topology\_description\_t

Status of MongoDB Servers

### Synopsis

```
typedef struct _mongoc_topology_description_t mongoc_topology_description_t;
```

**mongoc\_topology\_description\_t** is an opaque type representing the driver's knowledge of the MongoDB server or servers it is connected to. Its API conforms to the *SDAM Monitoring Specification*.

Applications receive a temporary reference to a **mongoc\_topology\_description\_t** as a parameter to an SDAM Monitoring callback that must not be destroyed. See *Introduction to Application Performance Monitoring*.

### mongoc\_transaction\_opt\_t

```
#include <mongoc/mongoc.h>
typedef struct _mongoc_transaction_opt_t mongoc_transaction_opt_t;
```

### Synopsis

Options for starting a multi-document transaction.

When a session is first created with *mongoc\_client\_start\_session()*, it inherits from the client the read concern, write concern, and read preference with which to start transactions. Each of these fields can be overridden independently. Create a *mongoc\_transaction\_opt\_t* with *mongoc\_transaction\_opts\_new()*, and pass a non-NULL option to any of the *mongoc\_transaction\_opt\_t* setter functions:

- •

  *mongoc\_transaction\_opts\_set\_read\_concern()*

- •

  *mongoc\_transaction\_opts\_set\_write\_concern()*

- •

  *mongoc\_transaction\_opts\_set\_read\_prefs()*

Pass the resulting transaction options to *mongoc\_client\_session\_start\_transaction()*. Each field set in the transaction options overrides the inherited client configuration.

### Example

example-transaction.c

```
/* gcc example-transaction.c -o example-transaction \
 *     $(pkg-config --cflags --libs libmongoc-1.0) */
/* ./example-transaction [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;
   mongoc_database_t *database = NULL;
   mongoc_collection_t *collection = NULL;
   mongoc_client_session_t *session = NULL;
   mongoc_session_opt_t *session_opts = NULL;
   mongoc_transaction_opt_t *default_txn_opts = NULL;
   mongoc_transaction_opt_t *txn_opts = NULL;
   mongoc_read_concern_t *read_concern = NULL;
   mongoc_write_concern_t *write_concern = NULL;
   const char *uri_string = "mongodb://127.0.0.1/?appname=transaction-example";
   mongoc_uri_t *uri;
   bson_error_t error;
   bson_t *doc = NULL;
   bson_t *insert_opts = NULL;
   int32_t i;
   int64_t start;
   bson_t reply = BSON_INITIALIZER;
   char *reply_json;
   bool r;
   mongoc_init ();
   if (argc > 1) {
      uri_string = argv[1];
   }
   uri = mongoc_uri_new_with_error (uri_string, &error);
   if (!uri) {
      MONGOC_ERROR ("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);
   database = mongoc_client_get_database (client, "example-transaction");
   /* inserting into a nonexistent collection normally creates it, but a
    * collection can't be created in a transaction; create it now */
   collection = mongoc_database_create_collection (database, "collection", NULL, &error);
   if (!collection) {
      /* code 48 is NamespaceExists, see error_codes.err in mongodb source */
      if (error.code == 48) {
         collection = mongoc_database_get_collection (database, "collection");
      } else {
         MONGOC_ERROR ("Failed to create collection: %s", error.message);
         goto done;
      }
   }
   /* a transaction's read preferences, read concern, and write concern can be
    * set on the client, on the default transaction options, or when starting
    * the transaction. for the sake of this example, set read concern on the
    * default transaction options. */
   default_txn_opts = mongoc_transaction_opts_new ();
   read_concern = mongoc_read_concern_new ();
   mongoc_read_concern_set_level (read_concern, "snapshot");
   mongoc_transaction_opts_set_read_concern (default_txn_opts, read_concern);
   session_opts = mongoc_session_opts_new ();
   mongoc_session_opts_set_default_transaction_opts (session_opts, default_txn_opts);
   session = mongoc_client_start_session (client, session_opts, &error);
   if (!session) {
      MONGOC_ERROR ("Failed to start session: %s", error.message);
      goto done;
   }
   /* in this example, set write concern when starting the transaction */
   txn_opts = mongoc_transaction_opts_new ();
   write_concern = mongoc_write_concern_new ();
   mongoc_write_concern_set_wmajority (write_concern, 1000 /* wtimeout */);
   mongoc_transaction_opts_set_write_concern (txn_opts, write_concern);
   insert_opts = bson_new ();
   if (!mongoc_client_session_append (session, insert_opts, &error)) {
      MONGOC_ERROR ("Could not add session to opts: %s", error.message);
      goto done;
   }
retry_transaction:
   r = mongoc_client_session_start_transaction (session, txn_opts, &error);
   if (!r) {
      MONGOC_ERROR ("Failed to start transaction: %s", error.message);
      goto done;
   }
   /* insert two documents - on error, retry the whole transaction */
   for (i = 0; i < 2; i++) {
      doc = BCON_NEW ("_id", BCON_INT32 (i));
      bson_destroy (&reply);
      r = mongoc_collection_insert_one (collection, doc, insert_opts, &reply, &error);
      bson_destroy (doc);
      if (!r) {
         MONGOC_ERROR ("Insert failed: %s", error.message);
         mongoc_client_session_abort_transaction (session, NULL);
         /* a network error, primary failover, or other temporary error in a
          * transaction includes {"errorLabels": ["TransientTransactionError"]},
          * meaning that trying the entire transaction again may succeed
          */
         if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
            goto retry_transaction;
         }
         goto done;
      }
      reply_json = bson_as_relaxed_extended_json (&reply, NULL);
      printf ("%s\n", reply_json);
      bson_free (reply_json);
   }
   /* in case of transient errors, retry for 5 seconds to commit transaction */
   start = bson_get_monotonic_time ();
   while (bson_get_monotonic_time () - start < 5 * 1000 * 1000) {
      bson_destroy (&reply);
      r = mongoc_client_session_commit_transaction (session, &reply, &error);
      if (r) {
         /* success */
         break;
      } else {
         MONGOC_ERROR ("Warning: commit failed: %s", error.message);
         if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
            goto retry_transaction;
         } else if (mongoc_error_has_label (&reply, "UnknownTransactionCommitResult")) {
            /* try again to commit */
            continue;
         }
         /* unrecoverable error trying to commit */
         break;
      }
   }
   exit_code = EXIT_SUCCESS;
done:
   bson_destroy (&reply);
   bson_destroy (insert_opts);
   mongoc_write_concern_destroy (write_concern);
   mongoc_read_concern_destroy (read_concern);
   mongoc_transaction_opts_destroy (txn_opts);
   mongoc_transaction_opts_destroy (default_txn_opts);
   mongoc_client_session_destroy (session);
   mongoc_collection_destroy (collection);
   mongoc_database_destroy (database);
   mongoc_uri_destroy (uri);
   mongoc_client_destroy (client);
   mongoc_cleanup ();
   return exit_code;
}
```

### mongoc\_transaction\_state\_t

Constants for transaction states

### Synopsis

```
typedef enum {
  MONGOC_TRANSACTION_NONE = 0,
  MONGOC_TRANSACTION_STARTING = 1,
  MONGOC_TRANSACTION_IN_PROGRESS = 2,
  MONGOC_TRANSACTION_COMMITTED = 3,
  MONGOC_TRANSACTION_ABORTED = 4,
} mongoc_transaction_state_t;
```

### Description

These constants describe the current transaction state of a session.

### Flag Values

| | |
| --- | --- |
| MONGOC\_TRANSACTION\_NONE | There is no transaction in progress. |
| MONGOC\_TRANSACTION\_STARTING | A transaction has been started, but no operation has been sent to the server. |
| MONGOC\_TRANSACTION\_IN\_PROGRESS | A transaction is in progress. |
| MONGOC\_TRANSACTION\_COMMITTED | The transaction was committed. |
| MONGOC\_TRANSACTION\_ABORTED | The transaction was aborted. |

### mongoc\_update\_flags\_t

Flags for update operations

### Synopsis

```
typedef enum {
   MONGOC_UPDATE_NONE = 0,
   MONGOC_UPDATE_UPSERT = 1 << 0,
   MONGOC_UPDATE_MULTI_UPDATE = 1 << 1,
} mongoc_update_flags_t;
#define MONGOC_UPDATE_NO_VALIDATE (1U << 31)
```

### Description

These flags correspond to the MongoDB wire protocol. They may be bitwise or'd together. The allow for modifying the way an update is performed in the MongoDB server.

### Flag Values

| | |
| --- | --- |
| MONGOC\_UPDATE\_NONE | No update flags set. |
| MONGOC\_UPDATE\_UPSERT | If an upsert should be performed. |
| MONGOC\_UPDATE\_MULTI\_UPDATE | If more than a single matching document should be updated. By default only the first document is updated. |
| MONGOC\_UPDATE\_NO\_VALIDATE | Do not perform client side BSON validations when performing an update. This is useful if you already know your BSON documents are valid. |

### mongoc\_uri\_t

### Synopsis

```
typedef struct _mongoc_uri_t mongoc_uri_t;
```

### Description

**mongoc\_uri\_t** provides an abstraction on top of the MongoDB connection URI format. It provides standardized parsing as well as convenience methods for extracting useful information such as replica hosts or authorization information.

See *Connection String URI Reference* on the MongoDB website for more information.

### Format

```
mongodb[+srv]://                             <1>
   [username:password@]                      <2>
   host1                                     <3>
   [:port1]                                  <4>
   [,host2[:port2],...[,hostN[:portN]]]      <5>
   [/[database]                              <6>
   [?options]]                               <7>
```

- 1\.

  "mongodb" is the specifier of the MongoDB protocol. Use "mongodb+srv" with a single service name in place of "host1" to specify the initial list of servers with an SRV record.

- 2\.

  An optional username and password.

- 3\.

  The only required part of the uri.  This specifies either a hostname, IPv4 address, IPv6 address enclosed in "\[" and "\]", or UNIX domain socket.

- 4\.

  An optional port number.  Defaults to :27017.

- 5\.

  Extra optional hosts and ports.  You would specify multiple hosts, for example, for connections to replica sets.

- 6\.

  The name of the database to authenticate if the connection string includes authentication credentials.  If /database is not specified and the connection string includes credentials, defaults to the 'admin' database.

- 7\.

  Connection specific options.

**NOTE:**

Option names are case-insensitive. Do not repeat the same option (e.g. "mongodb://localhost/db?opt=value1&OPT=value2") since this may have unexpected results.

The MongoDB C Driver exposes constants for each supported connection option. These constants make it easier to discover connection options, but their string values can be used as well.

For example, the following calls are equal.

```
uri = mongoc_uri_new ("mongodb://localhost/?" MONGOC_URI_APPNAME "=applicationName");
uri = mongoc_uri_new ("mongodb://localhost/?appname=applicationName");
uri = mongoc_uri_new ("mongodb://localhost/?appName=applicationName");
```

### Replica Set Example

To describe a connection to a replica set named 'test' with the following mongod hosts:

- •

  **db1.example.com** on port **27017**

- •

  **db2.example.com** on port **2500**

You would use a connection string that resembles the following.

```
mongodb://db1.example.com,db2.example.com:2500/?replicaSet=test
```

### SRV Example

If you have configured an *SRV record* with a name like "\_mongodb.\_tcp.server.example.com" whose records are a list of one or more MongoDB server hostnames, use a connection string like this:

```
uri = mongoc_uri_new ("mongodb+srv://server.example.com/?replicaSet=rs&appName=applicationName");
```

The driver prefixes the service name with "\_mongodb.\_tcp.", then performs a DNS SRV query to resolve the service name to one or more hostnames. If this query succeeds, the driver performs a DNS TXT query on the service name (without the "\_mongodb.\_tcp" prefix) for additional URI options configured as TXT records.

On Unix, the MongoDB C Driver relies on libresolv to look up SRV and TXT records. If libresolv is unavailable, then using a "mongodb+srv" URI will cause an error. If your libresolv lacks **res\_nsearch** then the driver will fall back to **res\_search**, which is not thread-safe.

Set the environment variable **MONGOC\_EXPERIMENTAL\_SRV\_PREFER\_TCP** to prefer TCP for the initial queries. The environment variable is ignored for **res\_search**. Large DNS responses over UDP may be truncated due to UDP size limitations. DNS resolvers are expected to retry over TCP if the UDP response indicates truncation. Some observed DNS environments do not set the truncation flag (TC), preventing the TCP retry. This environment variable is currently experimental and subject to change.

### 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.

### Connection Options

| | | | |
| --- | --- | --- | --- |
| Constant | Key | Default | Description |
| MONGOC\_URI\_RETRYREADS | retryreads | true | If "true" and the server is a MongoDB 3.6+ standalone, replica set, or sharded cluster, the driver safely retries a read that failed due to a network error or replica set failover. |
| MONGOC\_URI\_RETRYWRITES | retrywrites | true if driver built w/ TLS | If "true" and the server is a MongoDB 3.6+ replica set or sharded cluster, the driver safely retries a write that failed due to a network error or replica set failover. Only inserts, updates of single documents, or deletes of single documents are retried. |
| MONGOC\_URI\_APPNAME | appname | Empty (no appname) | The client application name. This value is used by MongoDB when it logs connection information and profile information, such as slow queries. |
| MONGOC\_URI\_TLS | tls | Empty (not set, same as false) | {true\|false}, indicating if TLS must be used. (See also *mongoc\_client\_set\_ssl\_opts()* and *mongoc\_client\_pool\_set\_ssl\_opts()*.) |
| MONGOC\_URI\_COMPRESSORS | compressors | Empty (no compressors) | Comma separated list of compressors, if any, to use to compress the wire protocol messages. Snappy, zlib, and zstd are optional build time dependencies, and enable the "snappy", "zlib", and "zstd" values respectively. |
| MONGOC\_URI\_CONNECTTIMEOUTMS | connecttimeoutms | 10,000 ms (10 seconds) | This setting applies to new server connections. It is also used as the socket timeout for server discovery and monitoring operations. |
| MONGOC\_URI\_SOCKETTIMEOUTMS | sockettimeoutms | 300,000 ms (5 minutes) | The time in milliseconds to attempt to send or receive on a socket before the attempt times out. |
| MONGOC\_URI\_REPLICASET | replicaset | Empty (no replicaset) | The name of the Replica Set that the driver should connect to. |
| MONGOC\_URI\_ZLIBCOMPRESSIONLEVEL | zlibcompressionlevel | -1 | When the MONGOC\_URI\_COMPRESSORS includes "zlib" this options configures the zlib compression level, when the zlib compressor is used to compress client data. |
| MONGOC\_URI\_LOADBALANCED | loadbalanced | false | If true, this indicates the driver is connecting to a MongoDB cluster behind a load balancer. |
| MONGOC\_URI\_SRVMAXHOSTS | srvmaxhosts | 0 | If zero, the number of hosts in DNS results is unlimited. If greater than zero, the number of hosts in DNS results is limited to being less than or equal to the given value. |

**WARNING:**

Setting any of the \*timeoutMS options above to either **0** or a negative value is discouraged due to unspecified and inconsistent behavior. The "default value" historically specified as a fallback for **0** or a negative value is NOT related to the default values for the \*timeoutMS options documented above. The meaning of a timeout of **0** or a negative value may vary depending on the operation being executed, even when specified by the same URI option. To specify the documented default value for a \*timeoutMS option, use the *MONGOC\_DEFAULT\_\** constants defined in **mongoc-client.h** instead.

### Authentication Options

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_AUTHMECHANISM | authmechanism | Specifies the mechanism to use when authenticating as the provided user. See *Authentication* for supported values. |
| MONGOC\_URI\_AUTHMECHANISMPROPERTIES | authmechanismproperties | Certain authentication mechanisms have additional options that can be configured. These options should be provided as comma separated option\_key:option\_value pair and provided as authMechanismProperties. Specifying the same option\_key multiple times has undefined behavior. |
| MONGOC\_URI\_AUTHSOURCE | authsource | The authSource defines the database that should be used to authenticate to. It is unnecessary to provide this option the database name is the same as the database used in the URI. |

### Mechanism Properties

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_CANONICALIZEHOSTNAME | canonicalizehostname | Use the canonical hostname of the service, rather than its configured alias, when authenticating with Cyrus-SASL Kerberos. |
| MONGOC\_URI\_GSSAPISERVICENAME | gssapiservicename | Use alternative service name. The default is **mongodb**. |

### TLS Options

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_TLS | tls | {true\|false}, indicating if TLS must be used. |
| MONGOC\_URI\_TLSCERTIFICATEKEYFILE | tlscertificatekeyfile | Path to PEM formatted Private Key, with its Public Certificate concatenated at the end. |
| MONGOC\_URI\_TLSCERTIFICATEKEYFILEPASSWORD | tlscertificatekeypassword | The password, if any, to use to unlock encrypted Private Key. |
| MONGOC\_URI\_TLSCAFILE | tlscafile | One, or a bundle of, Certificate Authorities whom should be considered to be trusted. |
| MONGOC\_URI\_TLSALLOWINVALIDCERTIFICATES | tlsallowinvalidcertificates | Accept and ignore certificate verification errors (e.g. untrusted issuer, expired, etc.) |
| MONGOC\_URI\_TLSALLOWINVALIDHOSTNAMES | tlsallowinvalidhostnames | Ignore hostname verification of the certificate (e.g. Man In The Middle, using valid certificate, but issued for another hostname) |
| MONGOC\_URI\_TLSINSECURE | tlsinsecure | {true\|false}, indicating if insecure TLS options should be used. Currently this implies MONGOC\_URI\_TLSALLOWINVALIDCERTIFICATES and MONGOC\_URI\_TLSALLOWINVALIDHOSTNAMES. |
| MONGOC\_URI\_TLSDISABLECERTIFICATEREVOCATIONCHECK | tlsdisablecertificaterevocationcheck | {true\|false}, indicates if revocation checking (CRL / OCSP) should be disabled. |
| MONGOC\_URI\_TLSDISABLEOCSPENDPOINTCHECK | tlsdisableocspendpointcheck | {true\|false}, indicates if OCSP responder endpoints should not be requested when an OCSP response is not stapled. |

See *Configuring TLS* for details about these options and about building libmongoc with TLS support.

### Deprecated SSL Options

The following options have been deprecated and may be removed from future releases of libmongoc.

| | | | |
| --- | --- | --- | --- |
| Constant | Key | Deprecated For | Key |
| MONGOC\_URI\_SSL | ssl | MONGOC\_URI\_TLS | tls |
| MONGOC\_URI\_SSLCLIENTCERTIFICATEKEYFILE | sslclientcertificatekeyfile | MONGOC\_URI\_TLSCERTIFICATEKEYFILE | tlscertificatekeyfile |
| MONGOC\_URI\_SSLCLIENTCERTIFICATEKEYPASSWORD | sslclientcertificatekeypassword | MONGOC\_URI\_TLSCERTIFICATEKEYFILEPASSWORD | tlscertificatekeypassword |
| MONGOC\_URI\_SSLCERTIFICATEAUTHORITYFILE | sslcertificateauthorityfile | MONGOC\_URI\_TLSCAFILE | tlscafile |
| MONGOC\_URI\_SSLALLOWINVALIDCERTIFICATES | sslallowinvalidcertificates | MONGOC\_URI\_TLSALLOWINVALIDCERTIFICATES | tlsallowinvalidcertificates |
| MONGOC\_URI\_SSLALLOWINVALIDHOSTNAMES | sslallowinvalidhostnames | MONGOC\_URI\_TLSALLOWINVALIDHOSTNAMES | tlsallowinvalidhostnames |

### Server Discovery, Monitoring, and Selection Options

Clients in a *mongoc\_client\_pool\_t* share a topology scanner that runs on a background thread. The thread wakes every **heartbeatFrequencyMS** (default 10 seconds) to scan all MongoDB servers in parallel. Whenever an application operation requires a server that is not known--for example, if there is no known primary and your application attempts an insert--the thread rescans all servers every half-second. In this situation the pooled client waits up to **serverSelectionTimeoutMS** (default 30 seconds) for the thread to find a server suitable for the operation, then returns an error with domain **MONGOC\_ERROR\_SERVER\_SELECTION**.

Technically, the total time an operation may wait while a pooled client scans the topology is controlled both by **serverSelectionTimeoutMS** and **connectTimeoutMS**. The longest wait occurs if the last scan begins just at the end of the selection timeout, and a slow or down server requires the full connection timeout before the client gives up.

A non-pooled client is single-threaded. Every **heartbeatFrequencyMS**, it blocks the next application operation while it does a parallel scan. This scan takes as long as needed to check the slowest server: roughly **connectTimeoutMS**. Therefore the default **heartbeatFrequencyMS** for single-threaded clients is greater than for pooled clients: 60 seconds.

By default, single-threaded (non-pooled) clients scan only once when an operation requires a server that is not known. If you attempt an insert and there is no known primary, the client checks all servers once trying to find it, then succeeds or returns an error with domain **MONGOC\_ERROR\_SERVER\_SELECTION**. But if you set **serverSelectionTryOnce** to "false", the single-threaded client loops, checking all servers every half-second, until **serverSelectionTimeoutMS**.

The total time an operation may wait for a single-threaded client to scan the topology is determined by **connectTimeoutMS** in the try-once case, or **serverSelectionTimeoutMS** and **connectTimeoutMS** if **serverSelectionTryOnce** is set "false".

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_HEARTBEATFREQUENCYMS | heartbeatfrequencyms | The interval between server monitoring checks. Defaults to 10,000ms (10 seconds) in pooled (multi-threaded) mode, 60,000ms (60 seconds) in non-pooled mode (single-threaded). |
| MONGOC\_URI\_SERVERSELECTIONTIMEOUTMS | serverselectiontimeoutms | A timeout in milliseconds to block for server selection before throwing an exception. The default is 30,0000ms (30 seconds). |
| MONGOC\_URI\_SERVERSELECTIONTRYONCE | serverselectiontryonce | If "true", the driver scans the topology exactly once after server selection fails, then either selects a server or returns an error. If it is false, then the driver repeatedly searches for a suitable server for up to **serverSelectionTimeoutMS** milliseconds (pausing a half second between attempts). The default for **serverSelectionTryOnce** is "false" for pooled clients, otherwise "true". Pooled clients ignore serverSelectionTryOnce; they signal the thread to rescan the topology every half-second until serverSelectionTimeoutMS expires. |
| MONGOC\_URI\_SOCKETCHECKINTERVALMS | socketcheckintervalms | Only applies to single threaded clients. If a socket has not been used within this time, its connection is checked with a quick "hello" call before it is used again. Defaults to 5,000ms (5 seconds). |
| MONGOC\_URI\_DIRECTCONNECTION | directconnection | If "true", the driver connects to a single server directly and will not monitor additional servers. If "false", the driver connects based on the presence and value of the **replicaSet** option. |

Setting any of the \*TimeoutMS options above to **0** will be interpreted as "use the default value".

### Connection Pool Options

These options govern the behavior of a *mongoc\_client\_pool\_t*. They are ignored by a non-pooled *mongoc\_client\_t*.

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_MAXPOOLSIZE | maxpoolsize | The maximum number of clients created by a *mongoc\_client\_pool\_t* total (both in the pool and checked out). The default value is 100. Once it is reached, *mongoc\_client\_pool\_pop()* blocks until another thread pushes a client. |
| MONGOC\_URI\_MINPOOLSIZE | minpoolsize | Deprecated. This option's behavior does not match its name, and its actual behavior will likely hurt performance. |
| MONGOC\_URI\_MAXIDLETIMEMS | maxidletimems | Not implemented. |
| MONGOC\_URI\_WAITQUEUEMULTIPLE | waitqueuemultiple | Not implemented. |
| MONGOC\_URI\_WAITQUEUETIMEOUTMS | waitqueuetimeoutms | The maximum time to wait for a client to become available from the pool. |

### Write Concern Options

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_W | w | Determines the write concern (guarantee). Valid values: 0 = The driver will not acknowledge write operations but will pass or handle any network and socket errors that it receives to the client. If you disable write concern but enable the getLastError command’s w option, w overrides the w option. 1 = Provides basic acknowledgement of write operations. By specifying 1, you require that a standalone mongod instance, or the primary for replica sets, acknowledge all write operations. For drivers released after the default write concern change, this is the default write concern setting. majority = For replica sets, if you specify the special majority value to w option, write operations will only return successfully after a majority of the configured replica set members have acknowledged the write operation. n = For replica sets, if you specify a number n greater than 1, operations with this write concern return only after n members of the set have acknowledged the write. If you set n to a number that is greater than the number of available set members or members that hold data, MongoDB will wait, potentially indefinitely, for these members to become available. tags = For replica sets, you can specify a tag set to require that all members of the set that have these tags configured return confirmation of the write operation. |
| MONGOC\_URI\_WTIMEOUTMS | wtimeoutms | The time in milliseconds to wait for replication to succeed, as specified in the w option, before timing out. When wtimeoutMS is 0, write operations will never time out. |
| MONGOC\_URI\_JOURNAL | journal | Controls whether write operations will wait until the mongod acknowledges the write operations and commits the data to the on disk journal. true = Enables journal commit acknowledgement write concern. Equivalent to specifying the getLastError command with the j option enabled. false = Does not require that mongod commit write operations to the journal before acknowledging the write operation. This is the default option for the journal parameter. |

### Read Concern Options

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_READCONCERNLEVEL | readconcernlevel | The level of isolation for read operations. If the level is left unspecified, the server default will be used. See *readConcern in the MongoDB Manual* for details. |

### Read Preference Options

When connected to a replica set, the driver chooses which member to query using the read preference:

- 1\.

  Choose members whose type matches "readPreference".

- 2\.

  From these, if there are any tags sets configured, choose members matching the first tag set. If there are none, fall back to the next tag set and so on, until some members are chosen or the tag sets are exhausted.

- 3\.

  From the chosen servers, distribute queries randomly among the server with the fastest round-trip times. These include the server with the fastest time and any whose round-trip time is no more than "localThresholdMS" slower.

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_READPREFERENCE | readpreference | Specifies the replica set read preference for this connection. This setting overrides any secondaryOk value. The read preference values are the following: primary (default) primaryPreferred secondary secondaryPreferred nearest |
| MONGOC\_URI\_READPREFERENCETAGS | readpreferencetags | A representation of a tag set. See also *Tag Sets*. |
| MONGOC\_URI\_LOCALTHRESHOLDMS | localthresholdms | How far to distribute queries, beyond the server with the fastest round-trip time. By default, only servers within 15ms of the fastest round-trip time receive queries. |
| MONGOC\_URI\_MAXSTALENESSSECONDS | maxstalenessseconds | The maximum replication lag, in wall clock time, that a secondary can suffer and still be eligible. The smallest allowed value for maxStalenessSeconds is 90 seconds. |

**NOTE:**

When connecting to more than one mongos, libmongoc's localThresholdMS applies only to the selection of mongos servers. The threshold for selecting among replica set members in shards is controlled by the *mongos's localThreshold command line option*.

### Legacy Options

For historical reasons, the following options are available. They should however not be used.

| | | |
| --- | --- | --- |
| Constant | Key | Description |
| MONGOC\_URI\_SAFE | safe | {true\|false} Same as w={1\|0} |

### Version Checks

Conditional compilation based on mongoc version

### Description

The following preprocessor macros can be used to perform various checks based on the version of the library you are compiling against. This may be useful if you only want to enable a feature on a certain version of the library.

```
#include <mongoc/mongoc.h>
#define MONGOC_MAJOR_VERSION (x)
#define MONGOC_MINOR_VERSION (y)
#define MONGOC_MICRO_VERSION (z)
#define MONGOC_VERSION_S     "x.y.z"
#define MONGOC_VERSION_HEX   ((1 << 24) | (0 << 16) | (0 << 8) | 0)
#define MONGOC_CHECK_VERSION(major, minor, micro)
```

Only compile a block on MongoDB C Driver 1.1.0 and newer.

```
#if MONGOC_CHECK_VERSION(1, 1, 0)
static void
do_something (void)
{
}
#endif
```

### mongoc\_write\_concern\_t

Write Concern abstraction

### Synopsis

**mongoc\_write\_concern\_t** tells the driver what level of acknowledgement to await from the server. The default, MONGOC\_WRITE\_CONCERN\_W\_DEFAULT, is right for the great majority of applications.

You can specify a write concern on connection objects, database objects, collection objects, or per-operation. Data-modifying operations typically use the write concern of the object they operate on, and check the server response for a write concern error or write concern timeout. For example, *mongoc\_collection\_drop\_index()* uses the collection's write concern, and a write concern error or timeout in the response is considered a failure.

Exceptions to this principle are the generic command functions:

- •

  *mongoc\_client\_command()*

- •

  *mongoc\_client\_command\_simple()*

- •

  *mongoc\_database\_command()*

- •

  *mongoc\_database\_command\_simple()*

- •

  *mongoc\_collection\_command()*

- •

  *mongoc\_collection\_command\_simple()*

These generic command functions do not automatically apply a write concern, and they do not check the server response for a write concern error or write concern timeout.

See *Write Concern* on the MongoDB website for more information.

### Write Concern Levels

Set the write concern level with *mongoc\_write\_concern\_set\_w()*.

| | |
| --- | --- |
| MONGOC\_WRITE\_CONCERN\_W\_DEFAULT (1) | By default, writes block awaiting acknowledgement from MongoDB. Acknowledged write concern allows clients to catch network, duplicate key, and other errors. |
| MONGOC\_WRITE\_CONCERN\_W\_UNACKNOWLEDGED (0) | With this write concern, MongoDB does not acknowledge the receipt of write operation. Unacknowledged is similar to errors ignored; however, mongoc attempts to receive and handle network errors when possible. |
| MONGOC\_WRITE\_CONCERN\_W\_MAJORITY (majority) | Block until a write has been propagated to a majority of the nodes in the replica set. |
| n | Block until a write has been propagated to at least **n** nodes in the replica set. |

### Deprecations

The write concern **MONGOC\_WRITE\_CONCERN\_W\_ERRORS\_IGNORED** (value -1) is a deprecated synonym for **MONGOC\_WRITE\_CONCERN\_W\_UNACKNOWLEDGED** (value 0), and will be removed in the next major release.

*mongoc\_write\_concern\_set\_fsync()* is deprecated.

### Application Performance Monitoring (APM)

The MongoDB C Driver allows you to monitor all the MongoDB operations the driver executes. This event-notification system conforms to two MongoDB driver specs:

- •

  *Command Logging and Monitoring*: events related to all application operations.

- •

  *SDAM Monitoring*: events related to the driver's Server Discovery And Monitoring logic.

To receive notifications, create a **mongoc\_apm\_callbacks\_t** with *mongoc\_apm\_callbacks\_new()*, set callbacks on it, then pass it to *mongoc\_client\_set\_apm\_callbacks()* or *mongoc\_client\_pool\_set\_apm\_callbacks()*.

### Command-Monitoring Example

example-command-monitoring.c

```
/* gcc example-command-monitoring.c -o example-command-monitoring \
 *     $(pkg-config --cflags --libs libmongoc-1.0) */
/* ./example-command-monitoring [CONNECTION_STRING] */
#include <mongoc/mongoc.h>
#include <stdio.h>
typedef struct {
   int started;
   int succeeded;
   int failed;
} stats_t;
void
command_started (const mongoc_apm_command_started_t *event)
{
   char *s;
   s = bson_as_relaxed_extended_json (mongoc_apm_command_started_get_command (event), NULL);
   printf ("Command %s started on %s:\n%s\n\n",
           mongoc_apm_command_started_get_command_name (event),
           mongoc_apm_command_started_get_host (event)->host,
           s);
   ((stats_t *) mongoc_apm_command_started_get_context (event))->started++;
   bson_free (s);
}
void
command_succeeded (const mongoc_apm_command_succeeded_t *event)
{
   char *s;
   s = bson_as_relaxed_extended_json (mongoc_apm_command_succeeded_get_reply (event), NULL);
   printf ("Command %s succeeded:\n%s\n\n", mongoc_apm_command_succeeded_get_command_name (event), s);
   ((stats_t *) mongoc_apm_command_succeeded_get_context (event))->succeeded++;
   bson_free (s);
}
void
command_failed (const mongoc_apm_command_failed_t *event)
{
   bson_error_t error;
   mongoc_apm_command_failed_get_error (event, &error);
   printf ("Command %s failed:\n\"%s\"\n\n", mongoc_apm_command_failed_get_command_name (event), error.message);
   ((stats_t *) mongoc_apm_command_failed_get_context (event))->failed++;
}
int
main (int argc, char *argv[])
{
   mongoc_client_t *client;
   mongoc_apm_callbacks_t *callbacks;
   stats_t stats = {0};
   mongoc_collection_t *collection;
   bson_error_t error;
   const char *uri_string = "mongodb://127.0.0.1/?appname=cmd-monitoring-example";
   mongoc_uri_t *uri;
   const char *collection_name = "test";
   bson_t *docs[2];
   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;
   }
   client = mongoc_client_new_from_uri (uri);
   if (!client) {
      return EXIT_FAILURE;
   }
   mongoc_client_set_error_api (client, 2);
   callbacks = mongoc_apm_callbacks_new ();
   mongoc_apm_set_command_started_cb (callbacks, command_started);
   mongoc_apm_set_command_succeeded_cb (callbacks, command_succeeded);
   mongoc_apm_set_command_failed_cb (callbacks, command_failed);
   mongoc_client_set_apm_callbacks (client, callbacks, (void *) &stats /* context pointer */);
   collection = mongoc_client_get_collection (client, "test", collection_name);
   mongoc_collection_drop (collection, NULL);
   docs[0] = BCON_NEW ("_id", BCON_INT32 (0));
   docs[1] = BCON_NEW ("_id", BCON_INT32 (1));
   mongoc_collection_insert_many (collection, (const bson_t **) docs, 2, NULL, NULL, NULL);
   /* duplicate key error on the second insert */
   mongoc_collection_insert_one (collection, docs[0], NULL, NULL, NULL);
   mongoc_collection_destroy (collection);
   mongoc_apm_callbacks_destroy (callbacks);
   mongoc_uri_destroy (uri);
   mongoc_client_destroy (client);
   printf ("started: %d\nsucceeded: %d\nfailed: %d\n", stats.started, stats.succeeded, stats.failed);
   bson_destroy (docs[0]);
   bson_destroy (docs[1]);
   mongoc_cleanup ();
   return EXIT_SUCCESS;
}
```

This example program prints:

```
Command drop started on 127.0.0.1:
{ "drop" : "test" }
Command drop succeeded:
{ "ns" : "test.test", "nIndexesWas" : 1, "ok" : 1.0 }
Command insert started on 127.0.0.1:
{
  "insert" : "test",
  "ordered" : true,
  "documents" : [
    { "_id" : 0 }, { "_id" : 1 }
  ]
}
Command insert succeeded:
{ "n" : 2, "ok" : 1.0 }
Command insert started on 127.0.0.1:
{
  "insert" : "test",
  "ordered" : true,
  "documents" : [
    { "_id" : 0 }
  ]
}
Command insert succeeded:
{
  "n" : 0,
  "writeErrors" : [
    { "index" : 0, "code" : 11000, "errmsg" : "duplicate key" }
  ],
  "ok" : 1.0
}
started: 3
succeeded: 3
failed: 0
```

The output has been edited and formatted for clarity. Depending on your server configuration, messages may include metadata like database name, logical session ids, or cluster times that are not shown here.

The final "insert" command is considered successful, despite the writeError, because the server replied to the overall command with **"ok": 1**.

### SDAM Monitoring Example

example-sdam-monitoring.c

```
/* gcc example-sdam-monitoring.c -o example-sdam-monitoring \
 *     $(pkg-config --cflags --libs libmongoc-1.0) */
/* ./example-sdam-monitoring [CONNECTION_STRING] */
#include <mongoc/mongoc.h>
#include <stdio.h>
typedef struct {
   int server_changed_events;
   int server_opening_events;
   int server_closed_events;
   int topology_changed_events;
   int topology_opening_events;
   int topology_closed_events;
   int heartbeat_started_events;
   int heartbeat_succeeded_events;
   int heartbeat_failed_events;
} stats_t;
static void
server_changed (const mongoc_apm_server_changed_t *event)
{
   stats_t *context;
   const mongoc_server_description_t *prev_sd, *new_sd;
   context = (stats_t *) mongoc_apm_server_changed_get_context (event);
   context->server_changed_events++;
   prev_sd = mongoc_apm_server_changed_get_previous_description (event);
   new_sd = mongoc_apm_server_changed_get_new_description (event);
   printf ("server changed: %s %s -> %s\n",
           mongoc_apm_server_changed_get_host (event)->host_and_port,
           mongoc_server_description_type (prev_sd),
           mongoc_server_description_type (new_sd));
}
static void
server_opening (const mongoc_apm_server_opening_t *event)
{
   stats_t *context;
   context = (stats_t *) mongoc_apm_server_opening_get_context (event);
   context->server_opening_events++;
   printf ("server opening: %s\n", mongoc_apm_server_opening_get_host (event)->host_and_port);
}
static void
server_closed (const mongoc_apm_server_closed_t *event)
{
   stats_t *context;
   context = (stats_t *) mongoc_apm_server_closed_get_context (event);
   context->server_closed_events++;
   printf ("server closed: %s\n", mongoc_apm_server_closed_get_host (event)->host_and_port);
}
static void
topology_changed (const mongoc_apm_topology_changed_t *event)
{
   stats_t *context;
   const mongoc_topology_description_t *prev_td;
   const mongoc_topology_description_t *new_td;
   mongoc_server_description_t **prev_sds;
   size_t n_prev_sds;
   mongoc_server_description_t **new_sds;
   size_t n_new_sds;
   size_t i;
   mongoc_read_prefs_t *prefs;
   context = (stats_t *) mongoc_apm_topology_changed_get_context (event);
   context->topology_changed_events++;
   prev_td = mongoc_apm_topology_changed_get_previous_description (event);
   prev_sds = mongoc_topology_description_get_servers (prev_td, &n_prev_sds);
   new_td = mongoc_apm_topology_changed_get_new_description (event);
   new_sds = mongoc_topology_description_get_servers (new_td, &n_new_sds);
   printf ("topology changed: %s -> %s\n",
           mongoc_topology_description_type (prev_td),
           mongoc_topology_description_type (new_td));
   if (n_prev_sds) {
      printf ("  previous servers:\n");
      for (i = 0; i < n_prev_sds; i++) {
         printf ("      %s %s\n",
                 mongoc_server_description_type (prev_sds[i]),
                 mongoc_server_description_host (prev_sds[i])->host_and_port);
      }
   }
   if (n_new_sds) {
      printf ("  new servers:\n");
      for (i = 0; i < n_new_sds; i++) {
         printf ("      %s %s\n",
                 mongoc_server_description_type (new_sds[i]),
                 mongoc_server_description_host (new_sds[i])->host_and_port);
      }
   }
   prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
   if (mongoc_topology_description_has_readable_server (new_td, prefs)) {
      printf ("  secondary AVAILABLE\n");
   } else {
      printf ("  secondary UNAVAILABLE\n");
   }
   if (mongoc_topology_description_has_writable_server (new_td)) {
      printf ("  primary AVAILABLE\n");
   } else {
      printf ("  primary UNAVAILABLE\n");
   }
   mongoc_read_prefs_destroy (prefs);
   mongoc_server_descriptions_destroy_all (prev_sds, n_prev_sds);
   mongoc_server_descriptions_destroy_all (new_sds, n_new_sds);
}
static void
topology_opening (const mongoc_apm_topology_opening_t *event)
{
   stats_t *context;
   context = (stats_t *) mongoc_apm_topology_opening_get_context (event);
   context->topology_opening_events++;
   printf ("topology opening\n");
}
static void
topology_closed (const mongoc_apm_topology_closed_t *event)
{
   stats_t *context;
   context = (stats_t *) mongoc_apm_topology_closed_get_context (event);
   context->topology_closed_events++;
   printf ("topology closed\n");
}
static void
server_heartbeat_started (const mongoc_apm_server_heartbeat_started_t *event)
{
   stats_t *context;
   context = (stats_t *) mongoc_apm_server_heartbeat_started_get_context (event);
   context->heartbeat_started_events++;
   printf ("%s heartbeat started\n", mongoc_apm_server_heartbeat_started_get_host (event)->host_and_port);
}
static void
server_heartbeat_succeeded (const mongoc_apm_server_heartbeat_succeeded_t *event)
{
   stats_t *context;
   char *reply;
   context = (stats_t *) mongoc_apm_server_heartbeat_succeeded_get_context (event);
   context->heartbeat_succeeded_events++;
   reply = bson_as_canonical_extended_json (mongoc_apm_server_heartbeat_succeeded_get_reply (event), NULL);
   printf (
      "%s heartbeat succeeded: %s\n", mongoc_apm_server_heartbeat_succeeded_get_host (event)->host_and_port, reply);
   bson_free (reply);
}
static void
server_heartbeat_failed (const mongoc_apm_server_heartbeat_failed_t *event)
{
   stats_t *context;
   bson_error_t error;
   context = (stats_t *) mongoc_apm_server_heartbeat_failed_get_context (event);
   context->heartbeat_failed_events++;
   mongoc_apm_server_heartbeat_failed_get_error (event, &error);
   printf (
      "%s heartbeat failed: %s\n", mongoc_apm_server_heartbeat_failed_get_host (event)->host_and_port, error.message);
}
int
main (int argc, char *argv[])
{
   mongoc_client_t *client;
   mongoc_apm_callbacks_t *cbs;
   stats_t stats = {0};
   const char *uri_string = "mongodb://127.0.0.1/?appname=sdam-monitoring-example";
   mongoc_uri_t *uri;
   bson_t cmd = BSON_INITIALIZER;
   bson_t reply;
   bson_error_t error;
   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;
   }
   client = mongoc_client_new_from_uri (uri);
   if (!client) {
      return EXIT_FAILURE;
   }
   mongoc_client_set_error_api (client, 2);
   cbs = mongoc_apm_callbacks_new ();
   mongoc_apm_set_server_changed_cb (cbs, server_changed);
   mongoc_apm_set_server_opening_cb (cbs, server_opening);
   mongoc_apm_set_server_closed_cb (cbs, server_closed);
   mongoc_apm_set_topology_changed_cb (cbs, topology_changed);
   mongoc_apm_set_topology_opening_cb (cbs, topology_opening);
   mongoc_apm_set_topology_closed_cb (cbs, topology_closed);
   mongoc_apm_set_server_heartbeat_started_cb (cbs, server_heartbeat_started);
   mongoc_apm_set_server_heartbeat_succeeded_cb (cbs, server_heartbeat_succeeded);
   mongoc_apm_set_server_heartbeat_failed_cb (cbs, server_heartbeat_failed);
   mongoc_client_set_apm_callbacks (client, cbs, (void *) &stats /* context pointer */);
   /* the driver connects on demand to perform first operation */
   BSON_APPEND_INT32 (&cmd, "buildinfo", 1);
   mongoc_client_command_simple (client, "admin", &cmd, NULL, &reply, &error);
   mongoc_uri_destroy (uri);
   mongoc_client_destroy (client);
   printf ("Events:\n"
           "   server changed: %d\n"
           "   server opening: %d\n"
           "   server closed: %d\n"
           "   topology changed: %d\n"
           "   topology opening: %d\n"
           "   topology closed: %d\n"
           "   heartbeat started: %d\n"
           "   heartbeat succeeded: %d\n"
           "   heartbeat failed: %d\n",
           stats.server_changed_events,
           stats.server_opening_events,
           stats.server_closed_events,
           stats.topology_changed_events,
           stats.topology_opening_events,
           stats.topology_closed_events,
           stats.heartbeat_started_events,
           stats.heartbeat_succeeded_events,
           stats.heartbeat_failed_events);
   bson_destroy (&cmd);
   bson_destroy (&reply);
   mongoc_apm_callbacks_destroy (cbs);
   mongoc_cleanup ();
   return EXIT_SUCCESS;
}
```

Start a 3-node replica set on localhost with set name "rs" and start the program:

```
./example-sdam-monitoring "mongodb://localhost:27017,localhost:27018/?replicaSet=rs"
```

This example program prints something like:

```
topology opening
topology changed: Unknown -> ReplicaSetNoPrimary
  secondary UNAVAILABLE
  primary UNAVAILABLE
server opening: localhost:27017
server opening: localhost:27018
localhost:27017 heartbeat started
localhost:27018 heartbeat started
localhost:27017 heartbeat succeeded: { ... reply ... }
server changed: localhost:27017 Unknown -> RSPrimary
server opening: localhost:27019
topology changed: ReplicaSetNoPrimary -> ReplicaSetWithPrimary
  new servers:
      RSPrimary localhost:27017
  secondary UNAVAILABLE
  primary AVAILABLE
localhost:27019 heartbeat started
localhost:27018 heartbeat succeeded: { ... reply ... }
server changed: localhost:27018 Unknown -> RSSecondary
topology changed: ReplicaSetWithPrimary -> ReplicaSetWithPrimary
  previous servers:
      RSPrimary localhost:27017
  new servers:
      RSPrimary localhost:27017
      RSSecondary localhost:27018
  secondary AVAILABLE
  primary AVAILABLE
localhost:27019 heartbeat succeeded: { ... reply ... }
server changed: localhost:27019 Unknown -> RSSecondary
topology changed: ReplicaSetWithPrimary -> ReplicaSetWithPrimary
  previous servers:
      RSPrimary localhost:27017
      RSSecondary localhost:27018
  new servers:
      RSPrimary localhost:27017
      RSSecondary localhost:27018
      RSSecondary localhost:27019
  secondary AVAILABLE
  primary AVAILABLE
topology closed
Events:
   server changed: 3
   server opening: 3
   server closed: 0
   topology changed: 4
   topology opening: 1
   topology closed: 1
   heartbeat started: 3
   heartbeat succeeded: 3
   heartbeat failed: 0
```

The driver connects to the mongods on ports 27017 and 27018, which were specified in the URI, and determines which is primary. It also discovers the third member, "localhost:27019", and adds it to the topology.

## AUTHOR

MongoDB, Inc

## COPYRIGHT

2009-present, MongoDB, Inc.
