| Crates.io | mongodb-ro |
| lib.rs | mongodb-ro |
| version | 2.3.0 |
| created_at | 2025-05-22 10:44:13.774206+00 |
| updated_at | 2025-08-16 09:35:01.84168+00 |
| description | A high-level, type-safe MongoDB model implementation |
| homepage | |
| repository | https://github.com/kak-smko/mongodb-ro |
| max_upload_size | |
| id | 1685010 |
| size | 129,311 |
A high-level, type-safe MongoDB model implementation with support for:
Boot, Serialize, and DeserializeOwned#[derive(Model)] for easy model setupcreated_at and updated_at timestampsAdd to your Cargo.toml:
[dependencies]
mongodb-ro = "2.1.0"
async fn get_db() -> Arc<Database> {
Arc::new(
Client::with_uri_str("mongodb://localhost:27017")
.await
.expect("failed to connect")
.database("test")
)
}
use std::sync::Arc;
use mongodb::bson::{doc, DateTime};
use mongodb::bson::oid::ObjectId;
use mongodb::{Client, Database};
use mongodb_ro::Model;
use serde::{Deserialize, Serialize};
use mongodb_ro::event::Boot;
#[derive(Serialize, Deserialize, Debug, Default, Model)]
#[model(collection="user")]
struct User {
_id: Option<ObjectId>,
name: String,
#[model(asc,unique)] // Creates ascending unique index
phone: String,
#[model(desc)] // Creates descending index
age: u8,
#[model(hidden, name("pswd"))] // Hidden by default and renamed in DB
password: String,
block: bool,
updated_at: Option<DateTime>,
created_at: Option<DateTime>,
}
impl Boot for User {
type Req = bool; // Request context type
}
use std::sync::Arc;
use mongodb::bson::{doc, DateTime};
use mongodb::bson::oid::ObjectId;
use mongodb::{Client, Database};
use mongodb_ro::Model;
use serde::{Deserialize, Serialize};
use mongodb_ro::event::Boot;
use actix_web::HttpRequest;
#[derive(Serialize, Deserialize, Debug, Default, Model)]
#[model(collection="user")]
struct User {
_id: Option<ObjectId>,
name: String,
#[model(asc,unique)] // Creates ascending unique index
phone: String,
#[model(desc)] // Creates descending index
age: u8,
#[model(hidden, name("pswd"))] // Hidden by default and renamed in DB
password: String,
block: bool,
updated_at: Option<DateTime>,
created_at: Option<DateTime>,
}
impl Boot for User {
type Req = HttpRequest; // Request context type
}
async fn save(req:HttpRequest) {
let db = get_db().await;
let mut user_model = User::new_model(&db).set_request(req);
user_model.name = "Smko".to_string();
user_model.phone = "123456789".to_string();
user_model.password = "1234".to_string();
user_model.create().await.unwrap();
}
Create a document:
async fn save() {
let db = get_db().await;
let mut user_model = User::new_model(&db);
user_model.name = "Smko".to_string();
user_model.phone = "123456789".to_string();
user_model.password = "1234".to_string();
user_model.create().await.unwrap();
}
Find documents:
async fn find_one() {
let db = get_db().await;
let user_model = User::new_model(&db);
// Find with visible password (normally hidden)
let user = user_model
.r#where(doc! {"name": "Smko"})
.visible(vec!["password"])
.first()
.await
.unwrap();
println!("Found user: {:?}", user);
}
Update documents:
async fn update() {
let db = get_db().await;
let user_model = User::new_model(&db);
// Simple update
user_model
.r#where(doc! {"name": "Smko"})
.update(doc! {"age": 3})
.await
.unwrap();
// Increment operation
user_model
.reset()
.r#where(doc! {"name": "Smko"})
.update(doc! {"$inc": {"age": 1}})
.await
.unwrap();
}
Delete documents:
async fn delete() {
let db = get_db().await;
let user_model = User::new_model(&db);
user_model
.r#where(doc! {"name": "Smko"})
.all()
.delete()
.await
.unwrap();
}
Transactions:
async fn transaction_with_session() {
let db = get_db().await;
let mut session = db.client().start_session().await.unwrap();
// Start transaction
session.start_transaction().await.unwrap();
// Create within transaction
let mut user_model = User::new_model(&db);
user_model.name = "TransactionUser".to_string();
user_model.phone = "987654321".to_string();
user_model.password = "txn_pass".to_string();
user_model.create_with_session(&mut session).await.unwrap();
// Verify within transaction
let user = User::new_model(&db)
.r#where(doc! {"name": "TransactionUser"})
.first_with_session(&mut session)
.await
.unwrap();
assert!(user.is_some());
// Commit
session.commit_transaction().await.unwrap();
// Cleanup
User::new_model(&db)
.r#where(doc! {"name": "TransactionUser"})
.delete()
.await
.unwrap();
}
Bulk operations:
async fn find_and_collect() {
let db = get_db().await;
let users = User::new_model(&db)
.get()
.await
.unwrap();
println!("All users: {:?}", users);
}
| Attribute | Description | Example |
|---|---|---|
collection |
Sets MongoDB collection name | #[model(collection="users")] |
| Attribute | Description | Example |
|---|---|---|
name |
Renames field in database | #[model(name="db_name")] |
hidden |
Hides field by default | #[model(hidden)] |
sphere2d |
Creates sphere2d index | #[model(sphere2d)] |
text |
Creates text index | #[model(text="en")] |
asc |
Creates ascending index | #[model(asc)] |
desc |
Creates descending index | #[model(desc)] |
unique |
Creates unique index | #[model(unique)] |
Contributions are welcome! Please open an issue or submit a PR for:
New features
Performance improvements
Bug fixes
Dual-licensed under MIT or Apache 2.0 at your option.