Il primo insert con mongosh: Guida completa all'inserimento di dati in MongoDB

Impara a inserire documenti in MongoDB utilizzando la shell mongosh. Scopri la differenza tra insertOne e insertMany e le best practice per la gestione dei dati.

Introduzione all'inserimento di dati in MongoDB

Benvenuti nella quinta lezione del nostro percorso "Impara MongoDB in 40 lezioni". Dopo aver compreso l'architettura di MongoDB, il concetto di database, collection e l'installazione della shell mongosh, è arrivato il momento di sporcarsi le mani. In questa lezione analizzeremo come inserire i primi dati all'interno del nostro database.

MongoDB è un database NoSQL orientato ai documenti. A differenza dei database relazionali (SQL), dove i dati devono essere inseriti in tabelle con schemi rigidi e predefiniti, MongoDB utilizza un formato simile al JSON chiamato BSON (Binary JSON). Questo significa che possiamo inserire documenti che possono avere strutture diverse tra loro all'interno della stessa collection. Tuttavia, per mantenere l'integrità e la manutenibilità del progetto, è fondamentale adottare una strategia di modellazione coerente.

In questa guida vedremo come utilizzare mongosh, l'interfaccia a riga di comando moderna per interagire con MongoDB, per eseguire le operazioni di scrittura. Impareremo non solo il "come", ma soprattutto il "perché" di certe scelte tecniche.

Comprendere la struttura del Documento

Prima di eseguire il primo comando di insert, dobbiamo capire cosa stiamo inserendo. In MongoDB, l'unità fondamentale di dati è il documento. Un documento è un insieme di coppie chiave-valore.

Il ruolo dell'ObjectId

Ogni documento in MongoDB deve avere un campo unico chiamato _id. Se non specifichiamo manualmente un valore per _id durante l'inserimento, MongoDB lo genererà automaticamente per noi. Questo campo è di tipo ObjectId, un identificatore unico a 12 byte che garantisce l'univocità del documento all'interno della collection e include informazioni temporali sulla creazione del record. È fondamentale non rimuovere mai questo campo, poiché è l'indice primario che permette ricerche ultra-rapide.

Tipi di dati supportati

Quando inseriamo dati, possiamo utilizzare diversi tipi di valori:

  • Stringhe: Per testi, nomi, email.
  • Numeri: Interi o decimali (double).
  • Booleani: true o false.
  • Date: Oggetti data specifici di MongoDB.
  • Array: Liste di valori o altri documenti.
  • Documenti nidificati: Un oggetto all'interno di un altro oggetto (Embedded Documents).

Eseguire il primo insertOne

Il metodo insertOne() è l'operazione più semplice per aggiungere un singolo documento a una collection. Se la collection specificata non esiste ancora, MongoDB la creerà automaticamente al momento del primo inserimento. Questo comportamento "schemaless" rende lo sviluppo estremamente agile.

Vediamo ora un esempio pratico. Immaginiamo di voler creare un database per una libreria e inserire il primo libro.

// 1. Selezioniamo il database (se non esiste, verrà creato al primo insert)
use libreria_db

// 2. Inseriamo un singolo documento nella collection 'libri'
db.libri.insertOne({
  titolo: "Il nome della rosa",
  autore: "Umberto Eco",
  anno_pubblicazione: 1980,
  generi: ["Giallo", "Storico"],
  disponibile: true,
  dettagli: {
    pagine: 500,
    editore: "Bompiani"
  }
});

Analisi del codice

In questo blocco di codice, abbiamo fatto diverse cose interessanti:

  1. use libreria_db: Abbiamo istruito la shell a lavorare sul database chiamato libreria_db.
  2. db.libri.insertOne(...): db è l'oggetto che rappresenta il database corrente, libri è il nome della collection e insertOne è il metodo per l'inserimento.
  3. Struttura nidificata: Abbiamo inserito un oggetto dettagli all'interno del documento. Questo è il cuore della potenza di MongoDB: non abbiamo bisogno di una tabella separata per i dettagli dell'editore, possiamo mantenere i dati correlati vicini.
  4. Array: Il campo generi è un array, permettendoci di associare più categorie a un singolo libro senza creare tabelle di giunzione.

Dopo l'esecuzione, mongosh restituirà un oggetto di conferma simile a questo: { acknowledged: true, insertedId: ObjectId("65a...") }.

Inserimento massivo con insertMany

Spesso non avremo bisogno di inserire un solo record, ma interi set di dati (ad esempio durante l'importazione di un catalogo). In questi casi, utilizzare insertOne in un ciclo sarebbe inefficiente a causa dei numerosi viaggi di rete (round-trip) tra il client e il server.

Il metodo insertMany() accetta un array di documenti e li inserisce in un'unica operazione atomica (per quanto riguarda l'invio della richiesta).

// Inserimento di più libri contemporaneamente
db.libri.insertMany([
  {
    titolo: "1984",
    autore: "George Orwell",
    anno_pubblicazione: 1949,
    generi: ["Distopia", "Politico"],
    disponibile: false
  },
  {
    titolo: "Il Signore degli Anelli",
    autore: "J.R.R. Tolkien",
    anno_pubblicazione: 1954,
    generi: ["Fantasy"],
    disponibile: true,
    dettagli: { pagine: 1200, editore: "HarperCollins" }
  },
  {
    titolo: "Fondazione",
    autore: "Isaac Asimov",
    anno_pubblicazione: 1951,
    generi: ["Fantascienza"],
    disponibile: true
  }
]);

Perché usare insertMany?

L'efficienza è il motivo principale. Quando inviamo un array di documenti, MongoDB ottimizza l'operazione di scrittura sul disco. Inoltre, insertMany restituisce un array di tutti gli insertedId generati, permettendoci di tenere traccia di tutti i nuovi record creati in un colpo solo.

Un aspetto importante da considerare è l'opzione ordered. Di default, insertMany è ordinato: se un inserimento fallisce (ad esempio per un duplicato di chiave), MongoDB si ferma e non processa i documenti successivi. Se impostiamo { ordered: false } come secondo parametro, MongoDB tenterà di inserire tutti i documenti, ignorando gli errori dei singoli record.

Esempi pratici e casi d'uso reali

Per rendere questa lezione più concreta, analizziamo come approcciare l'insert in scenari di sviluppo web reali.

Caso 1: Registrazione Utente

In un'applicazione Node.js, quando un utente si registra, non inseriremo solo il nome e l'email, ma potremmo voler salvare le preferenze di notifica in un unico documento per evitare JOIN costose in futuro.

db.utenti.insertOne({
  username: "dev_expert",
  email: "developer@example.com",
  password_hash: "a665a45920422f9...",
  profilo: {
    bio: "Appassionato di MongoDB e Web Dev",
    avatar: "/images/avatars/dev.jpg"
  },
  impostazioni: {
    notifiche_email: true,
    tema: "dark"
  },
  data_registrazione: new Date()
});

Caso 2: Log di Sistema

Per i sistemi di logging, dove la velocità di scrittura è critica, l'uso di insertMany è quasi obbligatorio. Spesso i log vengono accumulati in un buffer in memoria e poi "flushati" nel database ogni pochi secondi.

db.logs.insertMany([
  { timestamp: new Date(), livello: "INFO", messaggio: "User login successful", userId: 101 },
  { timestamp: new Date(), livello: "WARN", messaggio: "Slow query detected", duration: "500ms" },
  { timestamp: new Date(), livello: "ERROR", messaggio: "Connection timeout", code: 504 }
]);

Errori comuni e FAQ

Durante i primi passi con l'inserimento in MongoDB, è facile incorrere in alcuni errori classici. Ecco i più frequenti:

1. Dimenticare le virgole tra i campi

Poiché scriviamo in un formato simile a JSON, ogni coppia chiave-valore deve essere separata da una virgola. Un errore di sintassi qui bloccherà l'esecuzione del comando in mongosh.

2. Confondere insertOne con insert

Nelle versioni molto vecchie di MongoDB esisteva il metodo generico insert(). Sebbene sia ancora supportato in alcune versioni, è fortemente raccomandato utilizzare insertOne() o insertMany(). Questi metodi sono più espliciti e forniscono risposte più chiare sullo stato dell'operazione.

3. Inserire tipi di dati errati

Un errore comune è inserire una data come stringa ("2023-10-01") invece di usare l'oggetto new Date(). Se inserite le date come stringhe, non potrete utilizzare gli operatori di confronto di MongoDB (come $gt per "maggiore di") per filtrare i dati per intervallo temporale in modo efficiente.

FAQ veloce

Q: Posso cambiare lo schema di un documento dopo l'insert?

Sì, assolutamente. Puoi usare l'operatore $set con il metodo updateOne per aggiungere nuovi campi o modificare quelli esistenti in qualsiasi momento.

Q: Cosa succede se inserisco un documento con un _id che esiste già?

MongoDB restituirà un Duplicate Key Error. L'identificatore _id deve essere unico per ogni documento all'interno della stessa collection.

Prossimi passi

Ora che avete imparato a inserire dati in MongoDB, avete gettato le basi per costruire qualsiasi applicazione data-driven. Tuttavia, inserire dati è solo metà del lavoro; l'altra metà consiste nel saperli recuperare in modo efficiente.

Nelle prossime lezioni ci concentreremo su:

  1. La lettura dei dati: Impareremo a usare find() e findOne() per interrogare il database.
  2. I filtri di ricerca: Scopriremo come filtrare i risultati utilizzando gli operatori di query.
  3. L'aggiornamento dei documenti: Vedremo come modificare i dati esistenti con updateOne() e updateMany().

Per approfondire autonomamente, vi consiglio di esplorare la documentazione ufficiale di MongoDB riguardo ai BSON types per capire meglio come ottimizzare lo spazio di archiviazione dei vostri documenti. Provate a creare una collection di "Prodotti" per un e-commerce, sperimentando con array di tag e oggetti nidificati per le specifiche tecniche!