Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Rust e interazione con il database MongoDB

Creiamo con Rust un file di accesso ad un database MongoDB ed eseguiamolo per analizzare l'output generato
Creiamo con Rust un file di accesso ad un database MongoDB ed eseguiamolo per analizzare l'output generato
Link copiato negli appunti

In questa lezione ci occupiamo della creazione di un modulo per l'interazione con il database MongoDB. In particolare, creeremo due file. Il primo, denominato mongo_database.rs, imposterà tutti i metodi e le componenti per l'interazione con il database che assumeremo in esecuzione all'indirizzo localhost alla porta 27017/TCP. Il secondo file, main.rs, conterrà alcune operazioni di test per la verifica del funzionamento del primo. Si presti attenzione che solo il primo dei due file servirà nelle prossime lezioni mentre il secondo sarà un semplice test di cui ci avvarremo solo in questo articolo.

Iniziamo a costruire questa porzione del progetto.

Le dipendenze

Per prima cosa, indichiamo nel file Cargo.toml tutte le dipendenze di cui avremo bisogno:

[dependencies]
mongodb = "3.2.3"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
bson = "2.14"

Ciò innescherà lo scaricamento delle librerie indicate e di tutto il loro set di dipendenze. Per eseguire la preparazione del progetto, si può lanciare un comando cargo build.

Accedere al database MongoDB con Rust

Il codice che segue è il contenuto del file mongo_database.rs e costituirà, per tutto il resto dell'esempio, il codice di accesso al database al servizio della API REST:

// importazione delle librerie
use mongodb::{
    bson::{doc, oid::ObjectId, to_document, Document},
    options::ClientOptions, Client, Collection,
};
use serde::{Deserialize, Serialize};
// definizione della struttura Libro con serializzazione
#[derive(Debug, Serialize, Deserialize)]
pub struct Libro {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub titolo: String,
    pub autore: String,
    pub numero_pagine: i32,
}
// gestione del database
pub struct Database {
    collection: Collection<Libro>,
}
// metodi esemplificativi per operazioni CRUD più connessione
impl Database {
    pub async fn connect(uri: &str, db_name: &str, collection_name: &str) -> mongodb::error::Result<Self> {
        let client_options = ClientOptions::parse(uri).await?;
        let client = Client::with_options(client_options)?;
        let database = client.database(db_name);
        let collection = database.collection::<Libro>(collection_name);
        Ok(Self { collection })
    }
    pub async fn crea_libro(&self, libro: Libro) -> mongodb::error::Result<ObjectId> {
        let insert_result = self.collection.insert_one(libro).await?;
        Ok(insert_result.inserted_id.as_object_id().unwrap())
    }
    pub async fn leggi_libro(&self, id: ObjectId) -> mongodb::error::Result<Option<Libro>> {
        let filtro = doc! { "_id": id };
        let libro = self.collection.find_one(filtro).await?;
        Ok(libro)
    }
    pub async fn aggiorna_libro(&self, id: ObjectId, libro: Libro) -> mongodb::error::Result<()> {
        let filtro = doc! { "_id": id };
        let update = doc! { "$set": to_document(&libro)? };
        self.collection.update_one(filtro, update).await?;
        Ok(())
    }
    pub async fn cancella_libro(&self, id: ObjectId) -> mongodb::error::Result<()> {
        let filtro = doc! { "_id": id };
        self.collection.delete_one(filtro).await?;
        Ok(())
    }
}

Il codice del file mongo_database.rs

I punti salienti del codice sono:

  • importazione delle librerie: nelle prime righe predisponiamo il necessario per accesso a database e serializzazione/deserializzazione;
  • struct Libro: rappresenta, in Rust, la struttura dei documenti MongoDB che saranno salvati nel database. Questa è già predisposta per le varie operazioni di conversione in modo che si possa gestire sia l'inserimento di dati sia il loro recupero;
  • gestione dei dati: inizia con ciò che viene definito nel costrutto impl per definire le caratteristiche essenziali del trait. Nonostante non vengano tutti utilizzati in questo esempio, per completezza e possibili sviluppi personali della sperimentazione, abbiamo inserito un metodo per ogni operazione CRUD gestendo così ogni possibile caso di creazione, lettura, aggiornamento e cancellazione di documenti.

Test del codice per l'accesso al database MongoDB

Il precedente modulo può essere sperimentato con il file main.rs che come anticipato viene usato solo in questa lezione a scopo di test. Propone una sequenza di operazioni con cui
potremo collegarci al database MongoDB locale, creare un documento, verificarne la presenza, modificarne alcuni dati (titolo e numero pagine, in questo caso) ed infine cancellarlo:

mod mongo_database;
use mongo_database::{Database, Libro};
use mongodb::bson::oid::ObjectId;
#[tokio::main]
async fn main() -> mongodb::error::Result<()> {
    // connessione al database locale
    let db = Database::connect("mongodb://localhost:27017", "biblioteca", "libri").await?;
    // Primo esempio: creiamo un libro
    let nuovo_libro = Libro {
        id: None,
        titolo: "Manuale di giardinaggio".to_string(),
        autore: "Anna Marroni".to_string(),
        numero_pagine: 320,
    };
    let id_nuovo = db.crea_libro(nuovo_libro).await?;
    println!("Libro inserito = ID: {}", id_nuovo);
    // Verifica della creazione del libro
    if let Some(libro) = db.leggi_libro(id_nuovo).await? {
        println!("Dati recuperati dal db: {:?}", libro);
    }
    // Modifica dati relativi al libro
    let libro_aggiornato = Libro {
        id: Some(id_nuovo),
        titolo: "Manuale di giardinaggio (2° edizione)".to_string(),
        autore: "Anna Marroni".to_string(),
        numero_pagine: 386,
    };
    db.aggiorna_libro(id_nuovo, libro_aggiornato).await?;
    println!("Aggiornamento eseguito...");
    // Eliminazione di un oggetto dal database MongoDB
    db.cancella_libro(id_nuovo).await?;
    println!("Documento eliminato...");
    Ok(())
}

Output dell'esecuzione

L'output generato sarà il seguente:

Libro inserito = ID: 67fbd93afdd158f50d6ec894
Dati recuperati dal db: Libro { id: Some(ObjectId("67fbd93afdd158f50d6ec894")),
	titolo: "Manuale di giardinaggio",
	autore: "Anna Marroni",
	numero_pagine: 320 }
Aggiornamento eseguito...
Documento eliminato...

che dimostra come sia stato effettivamente generato un oggetto nel database MongoDB sebbene non mostri ancora i dati aggiornati che corrisponderanno a questa versione, estrapolata - in corso di esecuzione - dal database:

{
    _id: ObjectId('67fbd93afdd158f50d6ec894'),
    titolo: 'Manuale di giardinaggio (2° edizione)',
    autore: 'Anna Marroni',
    numero_pagine: 386
  }

Si tenga presente che le ultime righe del codice provvedono a cancellare il documento pertanto non sarà strano alla fine trovare il database vuoto. Per visionare i dati nel database MongoDB con mongosh, come abbiamo fatto noi, ci si può organizzare con operazioni di debug o semplicemente commentando le ultime righe e rieseguendo.

A questo punto, siamo pronti per creare le nostre API REST nella prossima lezione.

Ti consigliamo anche