Introducción: Por qué Rust y las bases de datos son una combinación ideal
Rust es un lenguaje de programación de sistemas moderno que combina el rendimiento de C/C++ con la seguridad de memoria garantizada por el compilador. Al desarrollar servicios backend, aplicaciones web y microservicios, casi siempre surge la necesidad de interactuar con bases de datos. En este artículo, analizaremos en detalle cómo trabajar con los dos tipos de bases de datos más populares: PostgreSQL relacional y MongoDB orientada a documentos.
Veremos la conexión, la ejecución de operaciones CRUD, transacciones y agregaciones con ejemplos prácticos. Todos los ejemplos de código están escritos en Rust utilizando el runtime asíncrono tokio, lo que proporciona el máximo rendimiento.
1. Configuración del proyecto e instalación de dependencias
Para empezar, crearemos un nuevo proyecto y añadiremos los crates necesarios. Abra la terminal y ejecute:
cargo new rust_db_examplecd rust_db_exampleAñadamos las dependencias al archivo Cargo.toml:
[dependencies]tokio = { version = "1", features = ["full"] }sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres"] }mongodb = "2.8"serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"chrono = { version = "0.4", features = ["serde"] }Ahora la estructura del proyecto está lista. Usaremos sqlx para PostgreSQL — un driver asíncrono con soporte para consultas compilables, y el driver oficial mongodb para trabajar con MongoDB.
1.1. Conexión a PostgreSQL mediante sqlx
Escribamos un módulo para trabajar con PostgreSQL. Cree el archivo src/postgres.rs:
use sqlx::postgres::PgPoolOptions;use sqlx::PgPool;use anyhow::Result;
pub async fn connect_to_postgres() -> Result<PgPool> { let database_url = "postgres://user:password@localhost:5432/mydb"; let pool = PgPoolOptions::new() .max_connections(5) .connect(database_url) .await?; println!("✅ Conectado a PostgreSQL"); Ok(pool)}
// Definimos el modelo de usuario#[derive(Debug, sqlx::FromRow)]pub struct User { pub id: i32, pub name: String, pub email: String, pub created_at: chrono::NaiveDateTime,}1.2. Conexión a MongoDB
Cree el archivo src/mongodb.rs:
use mongodb::{Client, Collection, Database};use mongodb::bson::{doc, Document};use anyhow::Result;
pub async fn connect_to_mongodb() -> Result<(Database, Collection<Document>)> { let client = Client::with_uri_str("mongodb://localhost:27017")?; let database = client.database("mydb"); let collection = database.collection::<Document>("users"); println!("✅ Conectado a MongoDB"); Ok((database, collection))}2. Operaciones CRUD en PostgreSQL
Ahora implementaremos las operaciones básicas: creación, lectura, actualización y eliminación de registros.
2.1. Inserción de datos (CREATE)
pub async fn create_user(pool: &PgPool, name: &str, email: &str) -> Result<User> { let user = sqlx::query_as::<_, User>( "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email, created_at" ) .bind(name) .bind(email) .fetch_one(pool) .await?; println!("Usuario creado: {:?}", user); Ok(user)}2.2. Lectura de datos (READ)
pub async fn get_user_by_id(pool: &PgPool, user_id: i32) -> Result<Option<User>> { let user = sqlx::query_as::<_, User>( "SELECT id, name, email, created_at FROM users WHERE id = $1" ) .bind(user_id) .fetch_optional(pool) .await?; match user { Some(u) => println!("Usuario encontrado: {:?}", u), None => println!("Usuario con id={} no encontrado"