HTML CSS JAVASCRIPT SQL MYSQL PYTHON JAVA PHP C C++ C# PACKET TRACER CYBERSECURITY REACT TYPESCRIPT NODE.JS GIT & GITHUB DATA SCIENCE BOOTSTRAP GO KOTLIN JQUERY DJANGO VUE ANGULAR MONGODB POSTGRESQL SASS NUMPY PANDAS SCIPY DSA RUST SWIFT BASHXMLW3.CSSANGULARJSAIAWSPROGRAMMAZIONEEXCEL WORD POWERPOINT
Corso gratuito

Corso MongoDB in italiano

Impara da zero il database NoSQL più popolare al mondo: documenti JSON, CRUD, aggregation pipeline, indici, schema validation e integrazione con Node.js. Con esempi pratici ed esercizi.

Introduzione a MongoDB

MongoDB è il database NoSQL più diffuso al mondo: invece di tabelle e righe usa documenti JSON (chiamati BSON internamente) organizzati in collezioni. È schemaless, orizzontalmente scalabile e progettato per dati flessibili e ad alta velocità.

A differenza di MySQL o PostgreSQL, in MongoDB non devi definire uno schema rigido in anticipo: ogni documento può avere campi diversi, ideale per dati variabili, log, cataloghi di prodotti e applicazioni real-time.

Perché usare MongoDB?

  • Flessibilità — nessuno schema obbligatorio, i documenti evolvono nel tempo
  • Performance — letture e scritture molto veloci su grandi volumi di dati
  • Scalabilità orizzontale — sharding nativo per distribuire i dati su più server
  • Dati annidati — array e oggetti dentro i documenti, senza JOIN
  • Cloud-native — MongoDB Atlas disponibile su AWS, Azure e GCP

Terminologia SQL ↔ MongoDB

SQLMongoDB
DatabaseDatabase
TabellaCollection
RigaDocument
ColonnaField
Primary Key_id (ObjectId)
JOIN$lookup / dati annidati
SELECTfind()
INSERTinsertOne() / insertMany()
UPDATEupdateOne() / updateMany()
DELETEdeleteOne() / deleteMany()
Esempio documento MongoDB
{
  "_id": ObjectId("64a1f2c3e8b7a3d0c9f12345"),
  "nome": "Mario Rossi",
  "eta": 28,
  "email": "mario@example.com",
  "indirizzo": {
    "via": "Via Roma 10",
    "citta": "Milano",
    "cap": "20100"
  },
  "hobbies": ["programmazione", "lettura", "ciclismo"],
  "attivo": true
}
💡 Ambiente consigliato: usa MongoDB Atlas (cloud gratuito) o MongoDB Compass per interfaccia grafica. Per la shell usa mongosh. Puoi esercitarti online su MongoDB Playground.

MongoDB — Per Iniziare

Puoi usare MongoDB in tre modi: localmente (installa MongoDB Community), nel cloud (MongoDB Atlas, cluster gratuito M0), o via Docker. Per chi inizia, Atlas è la scelta più rapida.

MongoDB Atlas (cloud) — setup in 5 minuti

  • Vai su mongodb.com/atlas e crea un account gratuito
  • Crea un cluster M0 (gratuito, 512 MB)
  • Aggiungi il tuo IP alla whitelist Network Access
  • Crea un utente database (username + password)
  • Ottieni la connection string: mongodb+srv://user:pass@cluster.mongodb.net/

Installazione locale (Ubuntu/Debian)

Installa MongoDB Community
# Importa la chiave GPG
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -

# Aggiungi il repository
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/7.0 multiverse" | \
  sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list

# Installa
sudo apt-get update && sudo apt-get install -y mongodb-org

# Avvia il servizio
sudo systemctl start mongod
sudo systemctl enable mongod

Installazione con Docker

MongoDB con Docker
# Avvia MongoDB in un container
docker run -d \
  --name mongodb \
  -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=secret \
  mongo:7.0

# Accedi alla shell MongoDB
docker exec -it mongodb mongosh -u admin -p secret

Primi comandi in mongosh

Primi passi con mongosh
// Mostra tutti i database
show dbs

// Usa (o crea) un database
use negozio

// Mostra le collezioni
show collections

// Inserisci un documento
db.prodotti.insertOne({ nome: "Laptop", prezzo: 999, stock: 50 })

// Leggi tutti i documenti
db.prodotti.find()

// Leggi con formattazione
db.prodotti.find().pretty()
🚀 Scorciatoia: use nomedb crea automaticamente il database la prima volta che inserisci un documento — non serve un comando separato "CREATE DATABASE".

MongoDB Query API

La Query API di MongoDB è il linguaggio con cui interroghi, filtri e trasformi i documenti. Tutte le operazioni si esprimono con oggetti JavaScript/JSON passati ai metodi della collezione.

Struttura base di una query

Struttura Query API
// Sintassi generale
db.collezione.metodo(filtro, opzioni)

// Esempi
db.utenti.find({ eta: 25 })                    // età = 25
db.utenti.find({ citta: "Roma" })              // città = Roma
db.utenti.find({ eta: { $gt: 18 } })           // età > 18
db.utenti.find({ $and: [{ attivo: true }, { eta: { $lt: 30 } }] })

Projection — scegliere i campi

Projection (include/escludi campi)
// Include solo nome ed email (1 = includi, 0 = escludi)
db.utenti.find(
  { attivo: true },
  { nome: 1, email: 1, _id: 0 }   // _id escluso esplicitamente
)

// Escludi solo un campo
db.utenti.find({}, { password: 0 })

Cursori e metodi di cursore

Metodi del cursore
// Limita i risultati
db.prodotti.find().limit(10)

// Salta i primi N documenti (paginazione)
db.prodotti.find().skip(20).limit(10)   // pagina 3 da 10

// Ordina: 1 = crescente, -1 = decrescente
db.prodotti.find().sort({ prezzo: -1 })  // più caro prima

// Conta i documenti
db.prodotti.countDocuments({ stock: { $gt: 0 } })

// Conta approssimato (velocissimo)
db.prodotti.estimatedDocumentCount()

Metodi utili

MetodoDescrizione
find(filtro)Restituisce cursore con tutti i match
findOne(filtro)Restituisce il primo documento match
countDocuments(filtro)Conta i documenti con il filtro
distinct(campo)Valori unici di un campo
find().limit(n)Limita a N risultati
find().sort(ord)Ordina i risultati
find().skip(n)Salta i primi N documenti
📌 find() restituisce un cursore (non tutti i documenti in memoria). Itera con forEach(), toArray() o in un loop for...of in Node.js per lavorare con i risultati.

MongoDB — Creare un Database

In MongoDB i database e le collezioni sono creati implicitamente al primo inserimento di un documento. Non esiste un comando CREATE DATABASE separato come in SQL.

Creare e selezionare un database

use — crea o seleziona un database
// Seleziona il database (lo crea se non esiste)
use scuola

// Il database viene creato fisicamente solo dopo il primo insert
db.studenti.insertOne({ nome: "Luca", eta: 20 })

// Ora il database "scuola" esiste
show dbs    // mostra scuola nell'elenco

// Vedi il database corrente
db

Creare una collezione esplicitamente

createCollection()
// Crea una collezione vuota (facoltativo)
db.createCollection("corsi")

// Con opzioni: capped collection (dimensione fissa, circolare)
db.createCollection("log", {
  capped: true,
  size: 1000000,   // max 1 MB
  max: 5000        // max 5000 documenti
})

// Con schema validation (JSON Schema)
db.createCollection("prodotti", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["nome", "prezzo"],
      properties: {
        nome:   { bsonType: "string" },
        prezzo: { bsonType: "number", minimum: 0 }
      }
    }
  }
})

Eliminare un database

dropDatabase()
// Seleziona il database da eliminare
use testdb

// Elimina il database corrente (IRREVERSIBILE)
db.dropDatabase()
⚠️ dropDatabase() elimina tutti i dati del database corrente in modo irreversibile. In produzione proteggi questa operazione con permessi appropriati.
💡 Convenzione: i nomi dei database MongoDB sono case-sensitive su Linux ma non su Windows. Usa sempre nomi in minuscolo con trattini o underscore per coerenza cross-platform.

MongoDB Collections

Una collection (collezione) è il contenitore dei documenti, equivalente a una tabella in SQL. A differenza delle tabelle, non richiede uno schema: ogni documento nella stessa collezione può avere campi completamente diversi.

Operazioni sulle collezioni

Gestione collezioni
// Crea collezione implicitamente
db.articoli.insertOne({ titolo: "Primo articolo" })

// Lista collezioni del database corrente
show collections
// oppure
db.getCollectionNames()

// Info su una collezione
db.articoli.stats()

// Rinomina una collezione
db.articoli.renameCollection("posts")

// Elimina una collezione e tutti i suoi dati
db.posts.drop()

Capped Collections

Le capped collections hanno dimensione fissa: quando piena, sovrascrive i documenti più vecchi (circolare). Perfette per log e dati temporali.

Capped collection per log
db.createCollection("access_log", {
  capped: true,
  size: 5242880,  // 5 MB
  max: 10000      // max 10.000 documenti
})

// I documenti vengono inseriti in ordine naturale (velocissimo)
db.access_log.insertOne({
  ip: "192.168.1.1",
  url: "/api/users",
  timestamp: new Date()
})

Time Series Collections

Time Series (MongoDB 5.0+)
// Ottimizzate per dati temporali (IoT, metriche)
db.createCollection("temperatura", {
  timeseries: {
    timeField: "timestamp",     // campo data obbligatorio
    metaField:  "sensore",      // campo metadati (facoltativo)
    granularity: "minutes"      // seconds | minutes | hours
  }
})

db.temperatura.insertOne({
  timestamp: new Date(),
  sensore: "sala-server",
  valore: 22.5
})
📌 MongoDB gestisce automaticamente l'_id di ogni documento: un ObjectId da 12 byte che include timestamp, machine ID e un contatore. Puoi sovrascriverlo con un valore custom: { _id: "custom-id", ... }

MongoDB — Insert

Per inserire documenti in una collezione si usano insertOne() (un documento) e insertMany() (array di documenti). Entrambi restituiscono i nuovi _id generati.

insertOne()

Inserisci un documento
// Inserisce un singolo documento
const result = db.prodotti.insertOne({
  nome: "Smartphone XZ",
  marca: "TechBrand",
  prezzo: 699.99,
  categorie: ["elettronica", "mobile"],
  specifiche: {
    ram: "8GB",
    storage: "256GB",
    colori: ["nero", "argento", "blu"]
  },
  disponibile: true,
  creato: new Date()
})

// L'_id generato
print(result.insertedId)  // ObjectId("64a1...")

insertMany()

Inserisci più documenti
// Inserisce un array di documenti
const result = db.studenti.insertMany([
  { nome: "Anna",  voto: 28, corso: "Informatica" },
  { nome: "Marco", voto: 30, corso: "Matematica"  },
  { nome: "Sofia", voto: 25, corso: "Informatica" },
  { nome: "Luca",  voto: 27, corso: "Fisica"      }
])

// IDs generati
print(result.insertedCount)  // 4
print(result.insertedIds)    // { 0: ObjectId, 1: ObjectId, ... }

Ordered vs Unordered Insert

Insert non ordinato (più performante)
// Per default insertMany è "ordered": si ferma al primo errore
// Con ordered:false continua anche in caso di errori parziali
db.prodotti.insertMany(
  [
    { _id: 1, nome: "A" },
    { _id: 1, nome: "B" },   // _id duplicato → errore
    { _id: 2, nome: "C" }
  ],
  { ordered: false }           // inserisce A e C, salta B
)

_id personalizzato

Usare _id custom
// Puoi usare qualsiasi valore come _id
db.paesi.insertMany([
  { _id: "IT", nome: "Italia",   capitale: "Roma"   },
  { _id: "FR", nome: "Francia",  capitale: "Parigi" },
  { _id: "DE", nome: "Germania", capitale: "Berlino"}
])

// Ricerca per _id custom
db.paesi.findOne({ _id: "IT" })
insertMany() con ordered: false è più veloce in bulk insert perché MongoDB non deve aspettare la conferma di ogni documento prima di inserire il successivo.

MongoDB — Find

I metodi find() e findOne() sono usati per interrogare i documenti. Il primo argomento è il filtro (oggetto query), il secondo è la projection (campi da includere/escludere).

Find base

find() e findOne()
// Tutti i documenti
db.prodotti.find()

// Filtro esatto
db.prodotti.find({ marca: "Apple" })

// findOne() — restituisce un solo documento (o null)
db.prodotti.findOne({ _id: ObjectId("64a1f2c3...") })

// Filtro su campo annidato (dot notation)
db.prodotti.find({ "indirizzo.citta": "Milano" })

// Filtro su elemento di array
db.prodotti.find({ categorie: "elettronica" })

Operatori di confronto nei filtri

OperatoreSignificatoEsempio
$eqUguale{ eta: { $eq: 25 } }
$neDiverso{ stato: { $ne: "inattivo" } }
$gtMaggiore{ prezzo: { $gt: 100 } }
$gteMaggiore o uguale{ voto: { $gte: 18 } }
$ltMinore{ eta: { $lt: 30 } }
$lteMinore o uguale{ eta: { $lte: 65 } }
$inIn un insieme{ citta: { $in: ["Roma","Milano"] } }
$ninNon in un insieme{ stato: { $nin: ["banned","deleted"] } }
Esempi con operatori di confronto
// Prodotti tra 50 e 200 euro
db.prodotti.find({ prezzo: { $gte: 50, $lte: 200 } })

// Utenti di Roma o Milano
db.utenti.find({ citta: { $in: ["Roma", "Milano"] } })

// Studenti con voto 28, 29 o 30
db.studenti.find({ voto: { $in: [28, 29, 30] } })

// Tutto tranne gli eliminati
db.utenti.find({ stato: { $nin: ["eliminato", "bannato"] } })

Operatori logici

$and, $or, $not, $nor
// $and implicito (default con più campi)
db.prodotti.find({ disponibile: true, prezzo: { $lt: 100 } })

// $or
db.prodotti.find({
  $or: [{ marca: "Apple" }, { marca: "Samsung" }]
})

// $and esplicito (quando serve sullo stesso campo)
db.prodotti.find({
  $and: [
    { prezzo: { $gte: 100 } },
    { prezzo: { $lte: 500 } }
  ]
})

// $not
db.prodotti.find({ prezzo: { $not: { $gt: 1000 } } })

MongoDB — Update

Per modificare documenti si usano updateOne(), updateMany() e replaceOne(). Le modifiche si specificano con update operators che iniziano con $.

updateOne() e updateMany()

Aggiorna documenti
// updateOne — modifica il primo documento che matcha
db.prodotti.updateOne(
  { nome: "Laptop Pro" },          // filtro
  { $set: { prezzo: 1199.99 } }    // aggiornamento
)

// updateMany — modifica tutti i documenti che matchano
db.prodotti.updateMany(
  { disponibile: false },
  { $set: { stock: 0 } }
)

// Risultato
// { matchedCount: 3, modifiedCount: 3 }

Operatori $set, $unset, $inc

Operatori di update comuni
// $set — imposta il valore di un campo
db.utenti.updateOne(
  { email: "mario@example.com" },
  { $set: { citta: "Torino", aggiornato: new Date() } }
)

// $unset — rimuove un campo dal documento
db.utenti.updateOne(
  { email: "mario@example.com" },
  { $unset: { vecchioIndirizzo: "" } }
)

// $inc — incrementa/decrementa un valore numerico
db.prodotti.updateOne(
  { nome: "Tastiera" },
  { $inc: { stock: -1, vendite: 1 } }  // -1 stock, +1 vendite
)

// $rename — rinomina un campo
db.utenti.updateMany({}, { $rename: { "nome": "firstName" } })

upsert — aggiorna o inserisci

upsert: true
// Se il documento non esiste lo crea (insert + update)
db.impostazioni.updateOne(
  { chiave: "tema" },
  { $set: { valore: "scuro", aggiornato: new Date() } },
  { upsert: true }           // crea se non trovato
)

replaceOne()

Sostituisci un documento intero
// Sostituisce l'INTERO documento (mantiene solo _id)
db.prodotti.replaceOne(
  { _id: ObjectId("64a1...") },
  {
    nome: "Laptop Pro Max",
    prezzo: 1499,
    marca: "Apple",
    aggiornato: new Date()
  }
)
📌 Differenza chiave: updateOne/Many modifica solo i campi specificati con gli operatori $; replaceOne sostituisce l'intero documento (eccetto _id).

MongoDB — Delete

Per eliminare documenti si usano deleteOne() (il primo match) e deleteMany() (tutti i match). Usa sempre un filtro preciso in produzione per evitare eliminazioni accidentali.

deleteOne() e deleteMany()
// Elimina il primo documento che matcha
db.prodotti.deleteOne({ nome: "Prodotto Obsoleto" })

// Elimina tutti i documenti che matchano
db.prodotti.deleteMany({ disponibile: false, stock: 0 })

// Elimina per _id (modo più sicuro)
db.ordini.deleteOne({ _id: ObjectId("64a1f2c3e8b7a3d0c9f12345") })

// ATTENZIONE: elimina TUTTI i documenti della collezione
db.temp_data.deleteMany({})

// Risultato
// { deletedCount: 3 }

findOneAndDelete()

Cancella e restituisce il documento
// Elimina e restituisce il documento eliminato in una sola operazione
const eliminato = db.sessioni.findOneAndDelete(
  { scaduta: true },
  { sort: { creata: 1 } }   // elimina la più vecchia
)

print(eliminato)  // il documento eliminato

Svuotare una collezione vs eliminarla

Drop vs deleteMany
// Elimina tutti i documenti (mantiene la collezione e gli indici)
db.cache.deleteMany({})

// Elimina la collezione e tutti i suoi indici (più veloce)
db.cache.drop()
⚠️ Non esiste un ROLLBACK in MongoDB per le delete (a meno di usare transazioni). Prima di un deleteMany in produzione, fai sempre un find() con lo stesso filtro per verificare cosa stai cancellando.
🛡️ Best practice: in applicazioni reali usa la tecnica del soft delete — aggiungi un campo { eliminato: true, eliminatoIl: new Date() } invece di cancellare fisicamente i dati.

MongoDB Query Operators

Gli operatori di query permettono di costruire filtri complessi: confronti, logica booleana, ricerca in array, espressioni regolari e molto altro.

Operatori su elementi

$exists, $type
// $exists — il campo esiste
db.utenti.find({ telefono: { $exists: true } })
db.utenti.find({ telefono: { $exists: false } })

// $type — tipo BSON del campo
db.dati.find({ valore: { $type: "string" } })
db.dati.find({ valore: { $type: "number" } })
db.dati.find({ valore: { $type: ["string", "null"] } })

Operatori su array

$all, $elemMatch, $size
// $all — contiene TUTTI gli elementi specificati
db.prodotti.find({ tags: { $all: ["sale", "nuovo"] } })

// $elemMatch — almeno un elemento soddisfa tutte le condizioni
db.studenti.find({
  voti: { $elemMatch: { $gte: 28, $lte: 30 } }
})

// $size — array di esattamente N elementi
db.ordini.find({ prodotti: { $size: 3 } })

// Accesso per indice (primo elemento dell'array)
db.studenti.find({ "voti.0": { $gte: 27 } })

Operatori di valutazione

$regex, $expr, $where
// $regex — espressione regolare (case-insensitive con $options)
db.prodotti.find({ nome: { $regex: "phone", $options: "i" } })
db.utenti.find({ email: { $regex: "@gmail\.com$" } })

// $expr — confronta campi dello stesso documento
db.ordini.find({
  $expr: { $gt: ["$totale", "$budget"] }  // totale > budget
})

// $mod — modulo aritmetico
db.numeri.find({ valore: { $mod: [4, 0] } })  // multipli di 4

Operatori geospaziali (cenni)

Query geospaziali
// Crea indice 2dsphere per coordinate GPS
db.ristoranti.createIndex({ posizione: "2dsphere" })

// Trova ristoranti entro 1km da un punto
db.ristoranti.find({
  posizione: {
    $near: {
      $geometry: { type: "Point", coordinates: [12.4924, 41.8902] },
      $maxDistance: 1000   // metri
    }
  }
})

MongoDB Update Operators

Gli operatori di update definiscono come modificare i documenti. Si dividono in operatori su campi, su array e su bit.

Operatori su campi

OperatoreAzione
$setImposta il valore di un campo
$unsetRimuove un campo
$incIncrementa/decrementa
$mulMoltiplica per un valore
$renameRinomina un campo
$minAggiorna solo se minore del valore attuale
$maxAggiorna solo se maggiore del valore attuale
$currentDateImposta la data corrente
$setOnInsertImposta valore solo in caso di upsert insert
Operatori su campi — esempi
// $mul — moltiplica
db.prodotti.updateMany({ saldo: true }, { $mul: { prezzo: 0.9 } })  // -10%

// $min / $max — aggiorna condizionalmente
db.punteggi.updateOne(
  { _id: userId },
  { $max: { highScore: 9500 } }  // aggiorna solo se 9500 > highScore attuale
)

// $currentDate — imposta timestamp corrente
db.ordini.updateOne(
  { _id: orderId },
  { $currentDate: { ultimaModifica: true } }
)

Operatori su array

OperatoreAzione
$pushAggiunge elemento in fondo
$popRimuove primo (-1) o ultimo (1) elemento
$pullRimuove elementi che matchano una condizione
$pullAllRimuove tutti i valori specificati
$addToSetAggiunge solo se non già presente (no duplicati)
$eachUsato con $push per aggiungere più elementi
$sortOrdina l'array dopo $push
$sliceMantiene solo gli ultimi N elementi
Operatori su array — esempi
// $push — aggiunge tag
db.articoli.updateOne(
  { _id: id },
  { $push: { tags: "mongodb" } }
)

// $addToSet — aggiunge solo se non esiste già
db.utenti.updateOne(
  { email: "user@example.com" },
  { $addToSet: { ruoli: "admin" } }
)

// $pull — rimuove elementi specifici
db.articoli.updateOne(
  { _id: id },
  { $pull: { tags: "bozza" } }
)

// $push + $each + $slice — mantieni solo ultimi 5 log
db.sessioni.updateOne(
  { userId: uid },
  {
    $push: {
      log: {
        $each:  [{ evento: "login", ts: new Date() }],
        $sort:  { ts: -1 },
        $slice: 5
      }
    }
  }
)

MongoDB Aggregations

L'Aggregation Pipeline è la funzionalità più potente di MongoDB: permette di trasformare e analizzare documenti attraverso una sequenza di stage (fasi), ognuna con un compito specifico.

Struttura della pipeline

Struttura base della pipeline
// La pipeline è un array di stage
db.collezione.aggregate([
  { $match: /* filtro */ },
  { $group: /* raggruppa */ },
  { $sort:  /* ordina */  },
  { $limit: /* limita */  },
  { $project: /* seleziona campi */ }
])

Stage principali

StageFunzione
$matchFiltra documenti (come WHERE in SQL)
$groupRaggruppa e aggrega (come GROUP BY)
$projectSeleziona/trasforma campi (come SELECT)
$sortOrdina i documenti
$limitLimita il numero di documenti
$skipSalta i primi N documenti
$lookupJOIN tra collezioni
$unwindEspande un campo array in più documenti
$addFieldsAggiunge campi calcolati
$countConta i documenti
$facetPipeline multiple in parallelo
Aggregazione — vendite per categoria
db.ordini.aggregate([
  // Stage 1: filtra solo ordini completati
  { $match: { stato: "completato" } },

  // Stage 2: raggruppa per categoria, somma il totale
  { $group: {
    _id:      "$categoria",
    totaleVendite: { $sum: "$importo" },
    numOrdini:     { $count: {} },
    mediaOrdine:   { $avg: "$importo" }
  }},

  // Stage 3: ordina per totale decrescente
  { $sort: { totaleVendite: -1 } },

  // Stage 4: rinomina _id in categoria
  { $project: {
    _id: 0,
    categoria: "$_id",
    totaleVendite: 1,
    numOrdini: 1,
    mediaOrdine: { $round: ["$mediaOrdine", 2] }
  }}
])

$lookup — JOIN tra collezioni

$lookup (equivalente JOIN)
// Unisce utenti con i loro ordini
db.utenti.aggregate([
  {
    $lookup: {
      from:         "ordini",      // collezione esterna
      localField:   "_id",         // campo locale
      foreignField: "userId",      // campo in ordini
      as:           "ordiniUtente" // nome del campo risultante
    }
  },
  // Filtra utenti con almeno un ordine
  { $match: { "ordiniUtente.0": { $exists: true } } }
])

$unwind — espandi array

$unwind
// Ogni prodotto di ogni ordine diventa un documento separato
db.ordini.aggregate([
  { $unwind: "$prodotti" },
  { $group: {
    _id:    "$prodotti.nome",
    totQty: { $sum: "$prodotti.quantita" }
  }},
  { $sort: { totQty: -1 } },
  { $limit: 5 }   // top 5 prodotti più venduti
])

MongoDB Indexing & Search

Gli indici sono fondamentali per le performance: senza di essi MongoDB fa una collection scan (legge tutti i documenti). Con un indice su un campo, le query su quel campo diventano logaritmicamente veloci.

Tipi di indice

TipoUso
Single fieldIndice su un singolo campo
CompoundIndice su più campi (ordine importante)
MultikeyIndice su campo array (automatico)
TextRicerca full-text su stringhe
2dsphereQuery geospaziali su coordinate GPS
HashedSharding su hash del campo
WildcardIndice su tutti i campi (schema flessibile)
PartialIndice solo su documenti che rispettano un filtro
TTLScadenza automatica dei documenti
Creare e gestire indici
// Indice singolo campo (1 = asc, -1 = desc)
db.utenti.createIndex({ email: 1 })

// Indice unico (nessun duplicato)
db.utenti.createIndex({ email: 1 }, { unique: true })

// Indice composto
db.prodotti.createIndex({ categoria: 1, prezzo: -1 })

// Indice text per ricerca full-text
db.articoli.createIndex({ titolo: "text", contenuto: "text" })

// TTL — elimina documenti dopo 3600 secondi
db.sessioni.createIndex(
  { creata: 1 },
  { expireAfterSeconds: 3600 }
)

// Lista indici
db.utenti.getIndexes()

// Elimina un indice
db.utenti.dropIndex({ email: 1 })

EXPLAIN — analizza le query

explain() per ottimizzare
// Analizza come MongoDB esegue la query
db.prodotti.find({ categoria: "elettronica" }).explain("executionStats")

// Cerca "IXSCAN" (usa indice) vs "COLLSCAN" (scansione totale)
// totalDocsExamined deve essere vicino a nReturned per essere efficiente

Atlas Search — full-text avanzato

Ricerca full-text con Atlas Search
// Con Atlas Search (solo MongoDB Atlas)
db.articoli.aggregate([
  {
    $search: {
      index: "default",
      text: {
        query: "mongodb tutorial italiano",
        path: ["titolo", "contenuto"],
        fuzzy: { maxEdits: 1 }  // tolleranza errori di battitura
      }
    }
  },
  { $limit: 10 },
  { $project: { titolo: 1, score: { $meta: "searchScore" } } }
])
⚡ Regola d'oro: crea indici sui campi usati in find(), sort(), $match e $lookup. Un indice composto { a: 1, b: 1 } copre anche query su solo a, ma non su solo b.

MongoDB Validation

MongoDB è schemaless per natura, ma puoi definire schema validation per imporre regole sui documenti: tipi obbligatori, valori consentiti, range numerici. Si usa il formato JSON Schema.

Aggiungere validation a una collezione

JSON Schema Validation
db.createCollection("utenti", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["nome", "email", "eta"],
      properties: {
        nome: {
          bsonType: "string",
          minLength: 2,
          maxLength: 100,
          description: "Nome obbligatorio, stringa 2-100 caratteri"
        },
        email: {
          bsonType: "string",
          pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
          description: "Email valida obbligatoria"
        },
        eta: {
          bsonType: "int",
          minimum: 0,
          maximum: 120
        },
        ruolo: {
          bsonType: "string",
          enum: ["utente", "admin", "moderatore"],
          description: "Deve essere uno dei valori consentiti"
        }
      }
    }
  },
  validationAction: "error",   // error | warn
  validationLevel:  "strict"   // strict | moderate | off
})

Aggiornare la validation esistente

collMod — modifica validazione
// Aggiorna la validazione di una collezione esistente
db.runCommand({
  collMod: "utenti",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["nome", "email"],
      properties: {
        nome:  { bsonType: "string" },
        email: { bsonType: "string" }
      }
    }
  },
  validationLevel: "moderate"  // valida solo i nuovi documenti
})

Tipi BSON supportati

bsonTypeDescrizione
stringStringa di testo
intIntero 32-bit
longIntero 64-bit
doubleNumero decimale
decimalDecimale ad alta precisione
booltrue / false
dateData/ora
objectIdObjectId MongoDB
arrayArray
objectOggetto/documento annidato
nullNull

MongoDB Data API

La MongoDB Data API (disponibile su Atlas) permette di interagire con i dati via HTTP REST senza installare driver. Ideale per applicazioni serverless, edge functions e webhook.

Abilitare la Data API su Atlas

  • In Atlas, vai su App ServicesData API
  • Abilita la Data API per il cluster desiderato
  • Genera una API Key dalla scheda Auth
  • Usa l'endpoint base: https://data.mongodb-api.com/app/<app-id>/endpoint/data/v1

Operazioni via HTTP

Find — HTTP POST
// Trova documenti via REST
fetch("https://data.mongodb-api.com/app/APP-ID/endpoint/data/v1/action/find", {
  method: "POST",
  headers: {
    "Content-Type":   "application/json",
    "api-key":        "TUA_API_KEY"
  },
  body: JSON.stringify({
    collection: "prodotti",
    database:   "negozio",
    dataSource: "Cluster0",
    filter:     { disponibile: true },
    projection: { nome: 1, prezzo: 1, _id: 0 },
    sort:       { prezzo: 1 },
    limit:      10
  })
})
.then(r => r.json())
.then(data => console.log(data.documents))
InsertOne via REST
fetch(".../action/insertOne", {
  method: "POST",
  headers: { "Content-Type": "application/json", "api-key": "KEY" },
  body: JSON.stringify({
    collection: "ordini",
    database:   "negozio",
    dataSource: "Cluster0",
    document: {
      prodotto: "Laptop",
      quantita: 1,
      totale:   999.99,
      data:     { $date: { $numberLong: Date.now().toString() } }
    }
  })
})
UpdateOne via REST
fetch(".../action/updateOne", {
  method: "POST",
  headers: { "Content-Type": "application/json", "api-key": "KEY" },
  body: JSON.stringify({
    collection: "prodotti",
    database:   "negozio",
    dataSource: "Cluster0",
    filter: { _id: { "$oid": "64a1f2c3e8b7a3d0c9f12345" } },
    update: { $inc: { stock: -1 } }
  })
})
📌 La Data API è ottima per prototipazione rapida e ambienti serverless. Per applicazioni ad alto volume (>1000 req/s) usa i driver nativi: sono significativamente più veloci grazie al connection pooling.

MongoDB Drivers

I driver ufficiali MongoDB sono disponibili per tutti i principali linguaggi di programmazione. Gestiscono automaticamente connection pooling, riconnessioni e conversione dei tipi BSON.

Driver disponibili

LinguaggioPacchettoInstallazione
Node.jsmongodbnpm install mongodb
Pythonpymongopip install pymongo
Javamongodb-driver-syncMaven/Gradle
C#/.NETMongoDB.Driverdotnet add package MongoDB.Driver
Gomongo-drivergo get go.mongodb.org/mongo-driver
PHPmongodbcomposer require mongodb/mongodb
Rustmongodbcargo add mongodb

Python — PyMongo

PyMongo — operazioni base
from pymongo import MongoClient
from datetime import datetime

# Connessione
client = MongoClient("mongodb+srv://user:pass@cluster.mongodb.net/")
db = client["negozio"]
col = db["prodotti"]

# Insert
col.insert_one({"nome": "Mouse", "prezzo": 29.99, "stock": 100})

# Find
for doc in col.find({"prezzo": {"$lt": 50}}, {"_id": 0, "nome": 1, "prezzo": 1}):
    print(doc)

# Update
col.update_one({"nome": "Mouse"}, {"$inc": {"stock": -1}})

# Delete
col.delete_one({"stock": 0})

client.close()

C# — MongoDB.Driver

C# Driver — operazioni base
using MongoDB.Driver;
using MongoDB.Bson;

var client = new MongoClient("mongodb+srv://user:pass@cluster/");
var db     = client.GetDatabase("negozio");
var col    = db.GetCollection<BsonDocument>("prodotti");

// Insert
await col.InsertOneAsync(new BsonDocument {
    { "nome",    "Tastiera"   },
    { "prezzo",  49.99        },
    { "stock",   75           }
});

// Find
var filtro = Builders<BsonDocument>.Filter.Gt("prezzo", 20);
var docs   = await col.Find(filtro).ToListAsync();

// Update
var update = Builders<BsonDocument>.Update.Inc("stock", -1);
await col.UpdateOneAsync(
    Builders<BsonDocument>.Filter.Eq("nome", "Tastiera"), update);

MongoDB Node.js Driver

Il driver Node.js ufficiale di MongoDB è mongodb. È la base di Mongoose (ODM più popolare) ma può essere usato direttamente per massime performance e controllo.

Installazione e connessione

Setup con Node.js
// Installazione
// npm install mongodb

const { MongoClient, ObjectId } = require("mongodb")

const URI = process.env.MONGODB_URI || "mongodb://localhost:27017"
const client = new MongoClient(URI, {
  maxPoolSize: 10,          // connection pool
  serverSelectionTimeoutMS: 5000
})

async function main() {
  await client.connect()
  const db  = client.db("negozio")
  const col = db.collection("prodotti")

  // CRUD
  await col.insertOne({ nome: "Monitor", prezzo: 349 })

  const prodotti = await col.find({ prezzo: { $lt: 400 } }).toArray()
  console.log(prodotti)

  await col.updateOne({ nome: "Monitor" }, { $set: { stock: 20 } })
  await col.deleteOne({ stock: 0 })
}

main().finally(() => client.close())

Mongoose — ODM per Node.js

Mongoose — Schema e Model
// npm install mongoose
const mongoose = require("mongoose")

mongoose.connect("mongodb+srv://user:pass@cluster/negozio")

// Definisci uno Schema
const prodottoSchema = new mongoose.Schema({
  nome:        { type: String,  required: true, trim: true },
  prezzo:      { type: Number,  required: true, min: 0     },
  stock:       { type: Number,  default: 0                 },
  categorie:   [String],
  creato:      { type: Date,    default: Date.now          }
})

// Aggiungi un metodo virtuale
prodottoSchema.virtual("disponibile").get(function() {
  return this.stock > 0
})

// Crea il Model
const Prodotto = mongoose.model("Prodotto", prodottoSchema)

// Usa il model
const laptop = new Prodotto({
  nome: "Laptop Dev", prezzo: 1299, stock: 15, categorie: ["informatica"]
})
await laptop.save()

// Query con Mongoose
const economici = await Prodotto.find({ prezzo: { $lt: 200 } })
                                .sort({ prezzo: 1 })
                                .limit(10)
                                .select("nome prezzo -_id")

Transazioni (sessioni ACID)

Transazioni multi-documento
// Le transazioni garantiscono atomicità su più collezioni
const session = client.startSession()
try {
  await session.withTransaction(async () => {
    const ordini  = db.collection("ordini")
    const magazzino = db.collection("magazzino")

    // Crea ordine e decrementa stock atomicamente
    await ordini.insertOne(
      { prodotto: "Laptop", qty: 1, totale: 1299 },
      { session }
    )
    await magazzino.updateOne(
      { nome: "Laptop" },
      { $inc: { stock: -1 } },
      { session }
    )
  })
  console.log("Transazione completata")
} catch (err) {
  console.error("Rollback automatico:", err.message)
} finally {
  await session.endSession()
}
📌 Mongoose vs driver nativo: Mongoose aggiunge validazione schema lato app, middleware (pre/post hooks), populate (equivalent $lookup semplificato) e metodi virtuali. Il driver nativo è più veloce ma più verboso.

MongoDB Charts

MongoDB Charts è lo strumento di visualizzazione dati integrato in Atlas: crea dashboard e grafici direttamente dai tuoi dati MongoDB, senza esportare o trasformare nulla.

Tipi di grafico disponibili

  • Bar / Column — confronto categorie
  • Line / Area — serie temporali e trend
  • Scatter / Bubble — correlazione tra variabili
  • Heatmap — distribuzione su griglia
  • Geo Map — dati geospaziali su mappa
  • Donut / Pie — proporzioni
  • Table — dati tabulari
  • Number — KPI singolo valore
  • Word Cloud — frequenza di termini testuali

Creare un grafico in Atlas

Pipeline di aggregazione per Charts
// MongoDB Charts esegue aggregations automaticamente,
// ma puoi anche inserire pipeline personalizzate.

// Esempio: vendite mensili per categoria
[
  { $match:  { stato: "completato" } },
  { $group: {
    _id: {
      mese:     { $month: "$data" },
      anno:     { $year:  "$data" },
      categoria: "$prodotto.categoria"
    },
    totale: { $sum: "$importo" }
  }},
  { $sort: { "_id.anno": 1, "_id.mese": 1 } }
]

Embedding di Charts in app esterne

Embed un grafico Charts via SDK
<!-- Aggiungi lo script SDK -->
<script src="https://charts.mongodb.com/charts-project/embeddings/charts-sdk.umd.min.js"></script>

<div id="chart"></div>

<script>
const sdk = ChartsEmbedSDK({
  baseUrl: "https://charts.mongodb.com/charts-project"
})

const chart = sdk.createChart({
  chartId:   "your-chart-id",
  height:    "500px",
  theme:     "dark",
  showAttribution: false
})

chart.render(document.getElementById("chart"))

// Filtro dinamico
chart.setFilter({ citta: "Milano" })
</script>
📊 MongoDB Charts si aggiorna in tempo reale (o con refresh configurabile). È ideale per dashboard operative, monitoraggio vendite, analytics di app mobile e report aziendali senza dover usare strumenti BI separati.

Esercizi MongoDB

Metti alla prova le tue conoscenze con questi esercizi pratici. Usa MongoDB Atlas o un ambiente locale con mongosh per eseguirli.

Esercizio 1 — Libreria digitale

📚 Base

Crea un database libreria con una collezione libri. Inserisci almeno 5 libri con i campi: titolo, autore, anno, genere (array), prezzo, disponibile (bool).

  • Trova tutti i libri disponibili
  • Trova i libri pubblicati dopo il 2000 ordinati per anno decrescente
  • Trova i libri del genere "fantasy" che costano meno di 20€
  • Aggiorna il prezzo di un libro con $inc
  • Aggiungi un nuovo genere a un libro con $addToSet

Esercizio 2 — Aggregation

📊 Intermedio

Usando la collezione libri dell'esercizio precedente, scrivi pipeline di aggregazione per:

  • Conta quanti libri ci sono per ogni genere
  • Calcola il prezzo medio per autore
  • Trova i 3 generi con il prezzo medio più alto
  • Elenca tutti i generi unici presenti (usa $unwind)

Esercizio 3 — E-commerce

🛒 Avanzato

Progetta un mini e-commerce con le collezioni: prodotti, utenti, ordini.

  • Crea schema validation per prodotti (nome, prezzo > 0, stock >= 0)
  • Scrivi una transazione che crea un ordine e decrementa lo stock atomicamente
  • Usa $lookup per ottenere gli ordini con i dati dell'utente allegati
  • Crea un indice TTL che elimina i carrelli abbandonati dopo 24 ore
  • Scrivi una pipeline che calcola le top 5 categorie per fatturato

Piano di Studio MongoDB

Segui questo percorso strutturato per padroneggiare MongoDB partendo da zero, con stima dei tempi per ogni fase.

SettimanaArgomentiObiettivo
1Intro, Atlas setup, mongosh, CRUD baseInserire, leggere, modificare ed eliminare documenti
2Query operators, projection, cursoriScrivere query complesse con filtri avanzati
3Aggregation pipeline, $group, $lookup, $unwindAnalizzare e trasformare i dati con le pipeline
4Indici, explain(), performanceOttimizzare le query con gli indici giusti
5Schema design, validation, transazioniProgettare schemi robusti per applicazioni reali
6Node.js driver, Mongoose, progetto finaleIntegrare MongoDB in un'applicazione Node.js completa

Risorse consigliate

Conclusione — E ora?

Complimenti! 🎉 Hai completato il corso MongoDB completo e gratuito in italiano: dall'installazione e i primi passi con mongosh, al CRUD completo, agli operatori di query e update, all'Aggregation Pipeline, agli indici, alla validation, alle transazioni ACID e all'integrazione con Node.js.

MongoDB è oggi uno dei database più richiesti nel mondo del lavoro: ogni azienda che gestisce dati flessibili, applicazioni real-time o grandi volumi di informazioni lo usa. Ora hai le basi per costruire applicazioni professionali con MongoDB.

E ora?

Hai già lavorato con Node.js e MongoDB: il passo successivo naturale è imparare PostgreSQL per confrontare il mondo NoSQL con un database relazionale potente, oppure approfondire il backend con Node.js per costruire API REST complete. Se vuoi un percorso guidato personalizzato, posso seguirti con ripetizioni di informatica in presenza a Roma.

🎯 La tua sfida finale

Costruisci un'API REST con Node.js + Express + MongoDB: un sistema di gestione libri con endpoint per creare, leggere, aggiornare ed eliminare libri. Aggiungi paginazione, ricerca full-text e uno schema Mongoose con validation. Deployala su Railway o Render con MongoDB Atlas come database. Sarà il progetto portfolio perfetto per dimostrare le tue competenze backend.

✏️ Provalo tu — leggi e modifica il codice MongoDB
Anteprima