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)]+ thebsoncrate'sdoc!macro for filters/updates; sessions and multi-document ACID transactions on replica sets; change streams asStreams. The oldbson::DateTime-vs-chronomapping 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/DeserializeRowderives; 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 FILTERINGas a smell — the data-storage theme owns the store-side rules. - DynamoDB:
aws-sdk-dynamodbis generated, verbose, and typed; serde_dynamo convertsHashMap<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
- Storage access from Rust — the map — parent map.
- Relational databases from Rust — where the modeling rigor lives when the data is actually relational.
- Databases and other storage systems — partitioning, consistency and the store-side internals.
- Document and NoSQL stores from Java and from Go — the counterparts; Rust's scylla crate is the standout of the three ecosystems for the Cassandra family.