Crate mongodb

source ·
Expand description

This crate contains the officially supported MongoDB Rust driver, a client side library that can be used to interact with MongoDB deployments in Rust applications. It uses the bson crate for BSON support. The driver contains a fully async API that supports either tokio (default) or async-std, depending on the feature flags set. The driver also has a sync API that may be enabled via the "sync" feature flag.

Installation

Requirements

  • Rust 1.57+
  • MongoDB 3.6+

Importing

The driver is available on crates.io. To use the driver in your application, simply add it to your project’s Cargo.toml.

[dependencies]
mongodb = "2.4.0"

Configuring the async runtime

The driver supports both of the most popular async runtime crates, namely tokio and async-std. By default, the driver will use tokio, but you can explicitly choose a runtime by specifying one of "tokio-runtime" or "async-std-runtime" feature flags in your Cargo.toml.

For example, to instruct the driver to work with async-std, add the following to your Cargo.toml:

[dependencies.mongodb]
version = "2.4.0"
default-features = false
features = ["async-std-runtime"]

Enabling the sync API

The driver also provides a blocking sync API. To enable this, add the "sync" or "tokio-sync" feature to your Cargo.toml:

[dependencies.mongodb]
version = "2.4.0"
features = ["tokio-sync"]

Using the "sync" feature also requires using default-features = false. Note: The sync-specific types can be imported from mongodb::sync (e.g. mongodb::sync::Client).

All Feature flags

FeatureDescriptionDefault
tokio-runtimeEnable support for the tokio async runtime.yes
async-std-runtimeEnable support for the async-std runtime.no
syncExpose the synchronous API (mongodb::sync), using an async-std backend. Cannot be used with the tokio-runtime feature flag.no
tokio-syncExpose the synchronous API (mongodb::sync), using a tokio backend. Cannot be used with the async-std-runtime feature flag.no
aws-authEnable support for the MONGODB-AWS authentication mechanism.no
bson-uuid-0_8Enable support for v0.8 of the uuid crate in the public API of the re-exported bson crate.no
bson-uuid-1Enable support for v1.x of the uuid crate in the public API of the re-exported bson crate.no
bson-chrono-0_4Enable support for v0.4 of the chrono crate in the public API of the re-exported bson crate.no
bson-serde_withEnable support for the serde_with crate in the public API of the re-exported bson crate.no
zlib-compressionEnable support for compressing messages with zlib.no
zstd-compressionEnable support for compressing messages with zstd.no
snappy-compressionEnable support for compressing messages with snappy.no
openssl-tlsSwitch TLS connection handling to use openssl.no
in-use-encryption-unstableEnable support for client-side field level encryption and queryable encryption. This API is unstable and may be subject to breaking changes in minor releases.no
tracing-unstableEnable support for emitting tracing events. This API is unstable and may be subject to breaking changes in minor releases.no

Example Usage

Using the async API

Connecting to a MongoDB deployment

use mongodb::{Client, options::ClientOptions};

// Parse a connection string into an options struct.
let mut client_options = ClientOptions::parse("mongodb://localhost:27017").await?;

// Manually set an option.
client_options.app_name = Some("My App".to_string());

// Get a handle to the deployment.
let client = Client::with_options(client_options)?;

// List the names of the databases in that deployment.
for db_name in client.list_database_names(None, None).await? {
    println!("{}", db_name);
}

Getting a handle to a database

// Get a handle to a database.
let db = client.database("mydb");

// List the names of the collections in that database.
for collection_name in db.list_collection_names(None).await? {
    println!("{}", collection_name);
}

Inserting documents into a collection

use mongodb::bson::{doc, Document};

// Get a handle to a collection in the database.
let collection = db.collection::<Document>("books");

let docs = vec![
    doc! { "title": "1984", "author": "George Orwell" },
    doc! { "title": "Animal Farm", "author": "George Orwell" },
    doc! { "title": "The Great Gatsby", "author": "F. Scott Fitzgerald" },
];

// Insert some documents into the "mydb.books" collection.
collection.insert_many(docs, None).await?;

A Collection can be parameterized with any type that implements the Serialize and Deserialize traits from the serde crate, not just Document:

# In Cargo.toml, add the following dependency.
serde = { version = "1.0", features = ["derive"] }
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Book {
    title: String,
    author: String,
}

// Get a handle to a collection of `Book`.
let typed_collection = db.collection::<Book>("books");

let books = vec![
    Book {
        title: "The Grapes of Wrath".to_string(),
        author: "John Steinbeck".to_string(),
    },
    Book {
        title: "To Kill a Mockingbird".to_string(),
        author: "Harper Lee".to_string(),
    },
];

// Insert the books into "mydb.books" collection, no manual conversion to BSON necessary.
typed_collection.insert_many(books, None).await?;

Finding documents in a collection

Results from queries are generally returned via Cursor, a struct which streams the results back from the server as requested. The Cursor type implements the Stream trait from the futures crate, and in order to access its streaming functionality you need to import at least one of the StreamExt or TryStreamExt traits.

# In Cargo.toml, add the following dependency.
futures = "0.3"
// This trait is required to use `try_next()` on the cursor
use futures::stream::TryStreamExt;
use mongodb::{bson::doc, options::FindOptions};

// Query the books in the collection with a filter and an option.
let filter = doc! { "author": "George Orwell" };
let find_options = FindOptions::builder().sort(doc! { "title": 1 }).build();
let mut cursor = typed_collection.find(filter, find_options).await?;

// Iterate over the results of the cursor.
while let Some(book) = cursor.try_next().await? {
    println!("title: {}", book.title);
}

Using the sync API

The driver also provides a blocking sync API. See the Installation section for instructions on how to enable it.

The various sync-specific types are found in the mongodb::sync submodule rather than in the crate’s top level like in the async API. The sync API calls through to the async API internally though, so it looks and behaves similarly to it.

use mongodb::{
    bson::doc,
    sync::Client,
};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Book {
    title: String,
    author: String,
}

let client = Client::with_uri_str("mongodb://localhost:27017")?;
let database = client.database("mydb");
let collection = database.collection::<Book>("books");

let docs = vec![
    Book {
        title: "1984".to_string(),
        author: "George Orwell".to_string(),
    },
    Book {
        title: "Animal Farm".to_string(),
        author: "George Orwell".to_string(),
    },
    Book {
        title: "The Great Gatsby".to_string(),
        author: "F. Scott Fitzgerald".to_string(),
    },
];

// Insert some books into the "mydb.books" collection.
collection.insert_many(docs, None)?;

let cursor = collection.find(doc! { "author": "George Orwell" }, None)?;
for result in cursor {
    println!("title: {}", result?.title);
}

Warning about timeouts / cancellation

In async Rust, it is common to implement cancellation and timeouts by dropping a future after a certain period of time instead of polling it to completion. This is how tokio::time::timeout works, for example. However, doing this with futures returned by the driver can leave the driver’s internals in an inconsistent state, which may lead to unpredictable or incorrect behavior (see RUST-937 for more details). As such, it is highly recommended to poll all futures returned from the driver to completion. In order to still use timeout mechanisms like tokio::time::timeout with the driver, one option is to spawn tasks and time out on their JoinHandle futures instead of on the driver’s futures directly. This will ensure the driver’s futures will always be completely polled while also allowing the application to continue in the event of a timeout.

e.g.

let collection = client.database("foo").collection("bar");
let handle = tokio::task::spawn(async move {
    collection.insert_one(doc! { "x": 1 }, None).await
});

tokio::time::timeout(Duration::from_secs(5), handle).await???;

Minimum supported Rust version (MSRV)

The MSRV for this crate is currently 1.57.0. This will be rarely be increased, and if it ever is, it will only happen in a minor or major version release.

Re-exports

Modules

  • Contains the functionality for change streams.
  • client_encryptionin-use-encryption-unstable
    Support for explicit encryption.
  • Contains the Error and Result types that mongodb uses.
  • Contains the events and functionality for monitoring internal Client behavior.
  • Contains the functionality for GridFS operations.
  • Contains all of the types needed to specify options to MongoDB operations.
  • Contains the types of results returned by CRUD operations.
  • syncsync or tokio-sync
    Contains the sync API. This is only available when the sync feature is enabled.

Structs

  • This is the main entry point for the API. A Client is used to connect to a MongoDB cluster. By default, it will monitor the topology of the cluster, keeping track of any changes, such as servers being added or removed.
  • A MongoDB client session. This struct represents a logical session used for ordering sequential operations. To create a ClientSession, call start_session on a Client.
  • Struct modeling a cluster time reported by the server.
  • Collection is the client-side abstraction of a MongoDB Collection. It can be used to perform collection-level operations such as CRUD operations. A Collection can be obtained through a Database by calling either Database::collection or Database::collection_with_options.
  • A Cursor streams the result of a query. When a query is made, the returned Cursor will contain the first batch of results from the server; the individual results will then be returned as the Cursor is iterated. When the batch is exhausted and if there are more results, the Cursor will fetch the next batch of documents, and so forth until the results are exhausted. Note that because of this batching, additional network I/O may occur on any given call to next. Because of this, a Cursor iterates over Result<T> items rather than simply T items.
  • Database is the client-side abstraction of a MongoDB database. It can be used to perform database-level operations or to obtain handles to specific collections within the database. A Database can only be obtained through a Client by calling either Client::database or Client::database_with_options.
  • A stream from which a file stored in a GridFS bucket can be downloaded.
  • A stream to which bytes can be written to be uploaded to a GridFS bucket.
  • Specifies the fields and options for an index. For more information, see the documentation.
  • A struct modeling the canonical name for a collection in MongoDB.
  • A description of the most up-to-date information known about a server. Further details can be found in the Server Discovery and Monitoring specification.
  • A SessionCursor is a cursor that was created with a ClientSession that must be iterated using one. To iterate, use SessionCursor::next or retrieve a SessionCursorStream using SessionCursor::stream:
  • A type that implements Stream which can be used to stream the results of a SessionCursor. Returned from SessionCursor::stream.

Enums

  • Enum representing the possible types of servers that the driver can connect to.
  • The possible types for a topology.