rgoussu@goussu: ~/library/rust/storage
~/library/rust/storage cat document-and-nosql.md

Document and NoSQL stores from Rust

# The official mongodb driver with bson/serde mapping, ScyllaDB's shard-aware scylla crate for Cassandra-family stores, and DynamoDB via aws-sdk-dynamodb with serde_dynamo.

Conceptsaved 2026-08-09 #rust#storage#mongodb#scylla#cassandra#dynamodb

Overview

The document/NoSQL corner is vendor-official across the board: MongoDB maintains the mongodb crate, ScyllaDB maintains scylla (which speaks CQL to Cassandra too, and is a better client than much of what other languages have for the same stores), and AWS's generated aws-sdk-dynamodb covers DynamoDB with serde_dynamo bridging its attribute-value types to serde. Mapping is serde everywhere — the "no entity manager, model with structs" posture shared with Go, against Java's framework data layers.

Key points

  • mongodb: async on Tokio, Collection<T> is generic over your serde type — #[derive(Serialize, Deserialize)] + the bson crate's doc! macro for filters/updates; sessions and multi-document ACID transactions on replica sets; change streams as Streams. The old bson::DateTime-vs-chrono mapping trip-up is handled with #[serde(with = "bson::serde_helpers::…")].
  • scylla: ScyllaDB's flagship client — shard-aware routing (requests go to the right core on the right node, Scylla's whole performance thesis), prepared statements, token-aware load balancing, SerializeRow/DeserializeRow derives; speaks CQL to Cassandra clusters as well, where it competes with cdrs-tokio and cassandra-cpp bindings and generally wins.
  • CQL discipline transfers unchanged: partition-key design, prepared-statements always, ALLOW FILTERING as a smell — the data-storage theme owns the store-side rules.
  • DynamoDB: aws-sdk-dynamodb is generated, verbose, and typed; serde_dynamo converts HashMap<String, AttributeValue> ↔ serde structs so items stay structs; single-table-design helpers exist (modyne) but the raw SDK + serde_dynamo is the norm.
  • Couchbase and CouchDB clients exist but are minor presences — the honest map marks them thin compared to the three above.
  • Testing: testcontainers-rs modules for MongoDB and ScyllaDB; DynamoDB Local in a container — same substrate as everything else.

Examples

#[derive(Serialize, Deserialize)]
struct Order {
    #[serde(rename = "_id")]
    id: ObjectId,
    customer: String,
    total_cents: i64,
}

let orders: Collection<Order> = client.database("shop").collection("orders");
let big = orders
    .find(doc! { "total_cents": { "$gte": 10_000 } })
    .await?
    .try_collect::<Vec<_>>()
    .await?;
// scylla: prepared + shard-aware
let prepared = session.prepare("INSERT INTO events (id, at, kind) VALUES (?, ?, ?)").await?;
session.execute_unpaged(&prepared, (id, at, kind)).await?;

Related