Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Work with BSON Data

In this guide, you can learn how the MongoDB Rust Driver and the bson crate represent BSON data, convert between BSON and Rust types, and work with BSON documents directly in your application code.

The driver uses the bson crate to encode and decode BSON data and uses the Serde framework to serialize and deserialize your Rust types. To learn more about serialization, see the Data Modeling and Serialization guide.

For more information about BSON and the full list of BSON types, see BSON Types in the MongoDB Server manual.

The examples in this guide use the following sample document, which represents a restaurant called "Mongo's Pizza" with an embedded address document and coordinates:

let mut restaurant: Document = doc! {
"address": {
"street": "Pizza St",
"zipcode": "10003",
},
"coord": [-73.982_419_f64, 41.579_505_f64],
"cuisine": "Pizza",
"name": "Mongo's Pizza",
};

MongoDB stores documents in a binary representation called BSON (Binary JSON). BSON supports all JSON data structure types and adds additional types such as dates, different-sized integers, ObjectId values, binary data, and more.

In the Rust ecosystem, the bson crate models BSON values by using the bson::Bson enum and BSON documents by using the bson::Document struct.

Tip

You don't need to add bson as a direct dependency if you are already using the mongodb crate. The driver re-exports bson, so you can import it from your application without a separate entry in your Cargo.toml file.

The bson crate provides the following core types and macros for working with BSON data:

  • bson::Bson: Enum that represents any BSON value, such as string, integer, document, or array.

  • bson::Document: Ordered map from UTF-8 string keys to Bson values that represents a BSON document.

  • bson! macro: Constructs a Bson value from a literal.

  • doc! macro: Constructs a Document from a literal.

For example, you can use the doc! macro to construct the sample restaurant document shown at the start of this guide.

You can access fields in a Document either as untyped Bson values or as strongly typed Rust values by using helper methods, as shown in the following example:

let value = restaurant.get("cuisine"); // Option<&Bson>
let name = restaurant.get_str("name")?; // &str
let address = restaurant.get_document("address")?; // &Document
let zipcode = address.get_str("zipcode")?; // &str

You can modify the contents of a Document by using standard map-like operations such as insertion, replacement, and removal, as shown in the following example:

restaurant = Document = doc! {
"address": {
"street": "Pizza St",
"zipcode": "10003",
},
"coord": [-73.982_419_f64, 41.579_505_f64],
"cuisine": "Pizza",
"name": "Mongo's Pizza",
};
// Adds a new field restaurant_id
restaurant.insert("restaurant_id", Bson::Int32(12345));
// Removes the cuisine field
restaurant.remove("cuisine");
// Updates the name field
if let Some(name) = restaurant.get_mut("name") {
*name = Bson::String("Mongo's Pizza Place".to_string());
}

Instead of working directly with Document values, you can model your collection data with custom Rust types. The driver and the bson crate integrate with Serde to serialize your types to BSON and deserialize BSON back into your types. To use a custom type as the generic parameter of a mongodb::Collection, derive the serde::Serialize and serde::Deserialize traits on your struct.

The following example defines a Restaurant struct that includes name, cuisine, and last_updated fields, parameterizes a collection by using this struct, and then constructs and inserts a Restaurant document with the current timestamp as the last_updated value:

#[derive(Serialize, Deserialize)]
struct Restaurant {
name: String,
cuisine: String,
last_updated: DateTime,
}
async fn use_collection(client: &Client) -> mongodb::error::Result<()> {
let coll: Collection<Restaurant> = client
.database("sample_restaurants")
.collection("restaurants");
let doc = Restaurant {
name: "Mongo's Pizza".to_string(),
cuisine: "Pizza".to_string(),
last_updated: DateTime::now(),
};
coll.insert_one(doc).await?;
Ok(())
}

When you parameterize a collection by using a custom type, the driver automatically serializes your type to BSON when writing and deserializes BSON back into your type when reading.

The bson crate provides Rust types that represent BSON value types, such as ObjectId and DateTime, which implement Serialize and Deserialize. You can embed these types directly in your domain structs to control how fields are serialized to and deserialized from BSON.

The following example defines an Order struct that uses the ObjectId type for the _id field and the DateTime type for the delivery_date field, ensuring that these fields are stored and retrieved as their corresponding BSON types:

#[derive(Serialize, Deserialize)]
struct Order {
_id: ObjectId,
item: String,
delivery_date: DateTime,
}

For additional customization options such as renaming fields, skipping fields, and how to use helper functions, see the Data Modeling and Serialization guide.

The bson crate models UUID values with the Uuid type, which corresponds to a BSON binary value with subtype 0x04 (UUID). With the appropriate feature flags, you can also integrate with the uuid crate through the bson::uuid module.

You can embed UUID values directly in your domain types, as shown in the following example:

#[derive(Serialize, Deserialize)]
struct Session {
id: Uuid,
user_id: Uuid,
created_at: DateTime,
}

Because the driver and bson integrate with Serde, UUID values are automatically serialized as BSON binary UUIDs and deserialized back into the appropriate Rust type.

For performance-sensitive workloads, you might want to inspect or validate BSON documents without fully deserializing them into strongly typed Rust structs. The bson crate exposes the following raw types for this purpose:

  • RawDocument - Borrowed slice of a BSON document, similar to str

  • RawDocumentBuf - Owned BSON document, similar to String

  • RawBsonRef - Borrowed reference to a single raw BSON value

You can create a RawDocumentBuf from a byte slice or Vec<u8> and then look up fields by key, as shown in the following example:

fn inspect_raw(bytes: Vec<u8>) -> Result<(), mongodb::bson::error::Error> {
let raw = RawDocumentBuf::from_bytes(bytes)?;
if let Some(name) = raw.get_str("name").ok() {
println!("Restaurant name: {name}");
}
Ok(())
}

These raw APIs let you access specific fields and validate document structure without allocating or deserializing entire documents into higher-level Rust types.

You can serialize a Document or any Serde-serializable type to its BSON wire-format representation and write it to disk. The bson crate provides the Document::to_vec() method to encode a document to its BSON byte representation.

The following example writes the sample restaurant document to a file:

fn write_bson_to_file(path: &str) -> std::io::Result<()> {
let restaurant: Document = doc! {
"address": {
"street": "Pizza St",
"zipcode": "10003",
},
"coord": [-73.982_419_f64, 41.579_505_f64],
"cuisine": "Pizza",
"name": "Mongo's Pizza",
};
// Encodes the document as BSON bytes
let bytes = restaurant.to_vec()
.expect("failed to encode document to BSON");
fs::write(path, &bytes)
}

To read BSON data from a file, you can load the raw bytes and then decode them into a Document or another Serde-serializable type. The bson crate supports reading documents directly from an in-memory buffer or reader.

The following example reads a BSON document from disk and prints it as Extended JSON for debugging:

fn read_bson_from_file(path: &str) -> Result<(), Box<dyn std::error::Error>> {
let bytes = fs::read(path)?;
let mut cursor = Cursor::new(bytes);
// Decodes a single document from the reader
let doc = Document::from_reader(&mut cursor)?;
// Converts to relaxed Extended JSON for logging
let bson_value = Bson::Document(doc);
let json = bson_value.into_relaxed_extjson(); // serde_json::Value
println!("{}", json);
Ok(())
}

The encoding and decoding helpers in the bson crate are designed to interoperate with MongoDB drivers and other BSON libraries, so you can use the same BSON representation both on disk and over the network.

To learn more about the types and methods described in this guide, see the following documentation:

Back

Collations

On this page