Per usare MongoDB da Node.js installa il driver ufficiale (npm install mongodb), connettiti con new MongoClient(uri), scegli un database con client.db('name') e una collection con db.collection('name'). Ogni operazione (insertOne, find, updateOne, deleteOne) restituisce una promise, quindi fai await. I documenti entrano ed escono come semplici oggetti JavaScript.
Stampa [ 'Dune', 'Neuromancer', 'Hyperion' ]. Il database shop e la collection books prima non esistevano: MongoDB li crea al primo inserimento, e toArray() carica tutti i documenti a cui punta il cursore di find().
Cercare documenti con filtri e projection
Un filtro è un oggetto che descrive i documenti che vuoi. I valori semplici devono corrispondere esattamente; operatori come $gt, $lt, $in e $regex vanno in un oggetto annidato. La projection del secondo argomento sceglie quali campi tornano indietro.
recent contiene i due libri più recenti dopo il 1960, prima Hyperion poi Neuromancer, con solo title e year; findOne restituisce la prima corrispondenza (o null), e countDocuments conta 2 libri che costano 10 o più. Cambia $gt: 1960 in $gt: 1985 e resta solo Hyperion.
Aggiornare ed eliminare
updateOne(filter, update) modifica il primo documento che corrisponde. L'aggiornamento usa degli operatori: $set sostituisce campi, $inc aggiunge a un numero, $unset toglie un campo e $push aggiunge in fondo a un array. updateMany e deleteMany agiscono su tutte le corrispondenze.
L'aggiornamento ha trovato e modificato un documento, quindi ora Dune costa 10 con 2 copie in magazzino, ed eliminando il libro senza scorte ne resta 1. Un aggiornamento deve usare gli operatori: passa { price: 10 } senza $set e il driver lo rifiuta (replaceOne è la chiamata che sostituisce un documento intero).
ObjectId e indici
Ogni documento riceve un _id; se non lo imposti tu, il driver crea un ObjectId. Per trovare un documento da un id arrivato come stringa (da un URL, per esempio), avvolgilo in new ObjectId(id). Un indice rende veloce la ricerca su un campo, e un indice unique fa rifiutare a MongoDB i duplicati.
Un ObjectId come stringa è lungo 24 caratteri esadecimali, e cercare con la stringa semplice non trova niente, quindi quella riga stampa null. Il secondo inserimento viola l'indice unique e fallisce con il codice 11000, che è il modo di capire che "l'email è già usata".
Usare MongoDB in un'API Express
Connettiti una volta sola all'avvio del server e condividi la collection; non aprire una nuova connessione per ogni richiesta. Il driver tiene un pool di connessioni e le riusa.
GET /books restituisce entrambi i libri, ognuno con un _id. Copia un id in GET /books/<id> per leggere un singolo libro, oppure invia POST /books con un body JSON come {"title": "Foundation", "year": 1951} ed elenca di nuovo i libri.
Un'app vera legge la stringa di connessione da process.env.MONGODB_URI invece di scriverla nel codice.
Se vuoi schemi e validazione sopra il driver, Mongoose (npm install mongoose) lo avvolge:
const Book = mongoose.model('Book', new mongoose.Schema({ title: String, year: Number }));
await Book.create({ title: 'Dune', year: 1965 });
Errori comuni
Dimenticare toArray(). find() restituisce un cursore, non documenti. Stamparlo mostra un oggetto cursore; chiama toArray() oppure scorrilo con for await.
Connettersi a ogni richiesta. Ogni new MongoClient apre il suo pool. Crea un solo client all'avvio e riusalo ovunque.
Non chiudere mai il client in uno script. Un client aperto tiene vivo il processo dopo che il codice ha finito. Chiama await client.close() alla fine degli script; un server lo tiene aperto per tutta la sua vita.
Domande frequenti
Meglio il driver mongodb o Mongoose?
Il driver è il livello ufficiale, più sottile: lavori con oggetti semplici e con il linguaggio di query di MongoDB. Mongoose ci aggiunge sopra schemi, validazione e modelli, utili quando vuoi che ogni documento sia controllato. Entrambi parlano con lo stesso database, e Mongoose usa il driver sotto.
Devo creare prima il database o la collection?
No. MongoDB li crea entrambi la prima volta che ci inserisci un documento. client.db('shop') e db.collection('books') restituiscono solo dei riferimenti.
Dove metto la stringa di connessione?
In una variabile d'ambiente come MONGODB_URI, letta con process.env.MONGODB_URI. La stringa di un database in hosting contiene una password, quindi non deve mai finire nel repository.
Perché find non restituisce documenti quando cerco per id?
_id è salvato come ObjectId, non come stringa, quindi { _id: '65f1...' } non trova niente. Convertilo prima: { _id: new ObjectId(id) }.