Iniziare con MongoDB
Impara a installare MongoDB, connetterti con PyMongo ed eseguire operazioni CRUD di base in Python con esempi chiari e funzionanti.
Questo capitolo introduce MongoDB e mostra come utilizzarlo da Python tramite il driver PyMongo. Al termine avrai MongoDB installato, una connessione funzionante e una visione chiara di come inserire, interrogare, aggiornare ed eliminare documenti.
Cos'è MongoDB?
MongoDB è un database di documenti — un tipo di database NoSQL che archivia i record come documenti in formato JSON invece di righe e colonne. Ogni documento è un oggetto autocontenuto che può avere campi annidati e array, il che lo rende particolarmente adatto per dati che non si adattano facilmente a uno schema fisso.
Caratteristiche principali:
- Schema flessibile. Due documenti nella stessa collection possono avere campi completamente diversi.
- Linguaggio di query ricco. Filtra, proietta, ordina, limita e aggrega con una singola chiamata al driver.
- Scalabilità orizzontale. Lo sharding integrato e i replica set gestiscono grandi volumi di dati e alta disponibilità.
- JSON nativo. I documenti sono archiviati come BSON (Binary JSON), quindi i dizionari Python si mappano direttamente ai documenti MongoDB.
Quando scegliere MongoDB rispetto a un database relazionale
| Situazione | Adatto? |
|---|---|
| Struttura dei dati in rapida evoluzione (prototipi, API) | Sì |
| Dati gerarchici / annidati | Sì |
Query complesse JOIN su più tabelle | Preferire SQL |
Transazioni ACID forti su molte tabelle | Preferire SQL |
| Ricerca full-text su larga scala | Combinare con Elasticsearch |
Installazione di MongoDB
Opzione 1 — Installazione locale
Scarica il MongoDB Community Server da mongodb.com/try/download/community, scegli il tuo sistema operativo e segui l'installer. Poi avvia il server:
# macOS / Linux
mongod --dbpath /data/db
# Windows (PowerShell, run as Administrator)
mongod --dbpath "C:\data\db"Verifica che MongoDB sia in esecuzione aprendo un secondo terminale e lanciando:
mongosh --eval "db.adminCommand('ping')"Output atteso:
{ ok: 1 }Opzione 2 — Docker (il più rapido per lo sviluppo)
Se hai Docker installato, puoi saltare l'installazione locale:
docker run -d --name mongo -p 27017:27017 mongo:7Questo scarica l'immagine ufficiale di MongoDB 7 ed espone la porta 27017 sulla tua macchina. Fermalo con docker stop mongo.
Opzione 3 — MongoDB Atlas (cloud)
Atlas è il servizio cloud completamente gestito di MongoDB con un piano gratuito. Dopo la registrazione, copia la stringa di connessione dalla dashboard — ha questo aspetto:
mongodb+srv://username:[email protected]/Puoi usare quell'URI ovunque vedi mongodb://localhost:27017/ in questo capitolo.
Installazione del driver PyMongo
PyMongo è il driver Python ufficiale per MongoDB. Installalo con pip:
pip install pymongoPer usare MongoDB Atlas, installa anche i componenti aggiuntivi che includono il resolver DNS:
pip install "pymongo[srv]"Verifica l'installazione:
import pymongo
print(pymongo.version)
# e.g. 4.7.3Connessione a MongoDB
MongoClient è il punto di ingresso per tutte le operazioni del driver. Crea un solo client per applicazione e riutilizzalo — il client gestisce internamente un connection pool.
from pymongo import MongoClient
# Local server with default host and port
client = MongoClient("mongodb://localhost:27017/")
# Verify connectivity (raises ConnectionFailure if the server is unreachable)
client.admin.command("ping")
print("Connected successfully")Per il codice in produzione, gestisci sempre gli errori di connessione in modo esplicito:
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure
client = MongoClient("mongodb://localhost:27017/", serverSelectionTimeoutMS=3000)
try:
client.admin.command("ping")
print("Connected to MongoDB")
except ConnectionFailure as e:
print("Connection failed:", e)Formato della stringa di connessione
mongodb://[username:password@]host[:port][/database][?options]Opzioni comuni:
| Opzione | Esempio | Scopo |
|---|---|---|
authSource | authSource=admin | Database usato per l'autenticazione |
replicaSet | replicaSet=rs0 | Connessione a un replica set |
tls=true | tls=true | Abilitazione TLS/SSL |
serverSelectionTimeoutMS | serverSelectionTimeoutMS=5000 | Timeout per la selezione del server |
Database e Collection
MongoDB organizza i dati in una gerarchia a due livelli:
- Un database raggruppa collection correlate (simile a uno schema o database SQL).
- Una collection contiene documenti (simile a una tabella SQL, ma senza schema fisso).
Entrambi vengono creati in modo lazy — vengono generati la prima volta che inserisci un documento. Non è mai necessario eseguire CREATE DATABASE o CREATE TABLE.
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017/")
# Reference a database (not yet created on disk)
db = client["mystore"]
# Reference a collection inside it (also not yet on disk)
products = db["products"]
# The database and collection are created when the first document is insertedOperazioni CRUD di base
Gli esempi seguenti si costruiscono uno sull'altro. Eseguili nell'ordine se stai seguendo in modo interattivo.
Create — inserire documenti
Usa insert_one() per un singolo documento e insert_many() per un batch:
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017/")
db = client["mystore"]
products = db["products"]
# Insert a single document
result = products.insert_one({
"name": "Laptop",
"brand": "Acme",
"price": 999.99,
"in_stock": True
})
print("Inserted id:", result.inserted_id)
# Insert multiple documents at once
new_products = [
{"name": "Mouse", "brand": "Acme", "price": 29.99, "in_stock": True},
{"name": "Keyboard", "brand": "Acme", "price": 79.99, "in_stock": False},
{"name": "Monitor", "brand": "Zeta", "price": 349.99, "in_stock": True},
]
batch_result = products.insert_many(new_products)
print("Inserted ids:", batch_result.inserted_ids)MongoDB aggiunge automaticamente un campo _id (di tipo ObjectId) a ogni documento se non ne fornisci uno. Questo campo è la chiave primaria ed è sempre univoco all'interno di una collection.
Read — interrogare i documenti
find_one() restituisce il primo documento corrispondente (o None). find() restituisce un cursore su cui puoi iterare.
# Retrieve one document (no filter = the first document in natural order)
doc = products.find_one()
print(doc)
# Retrieve all documents in the collection
for p in products.find():
print(p["name"], "-", p["price"])
# Filter: products that are in stock
for p in products.find({"in_stock": True}):
print(p["name"])
# Projection: return only name and price (exclude _id)
for p in products.find({}, {"_id": 0, "name": 1, "price": 1}):
print(p)Operatori di query
Il linguaggio di query di MongoDB usa operatori con prefisso $:
# Products cheaper than £100
cheap = products.find({"price": {"$lt": 100}})
# In-stock products from brand "Acme" or "Zeta"
multi = products.find({
"in_stock": True,
"brand": {"$in": ["Acme", "Zeta"]}
})
# Price between 50 and 500 (inclusive)
range_q = products.find({"price": {"$gte": 50, "$lte": 500}})Operatori di confronto comuni:
| Operatore | Significato |
|---|---|
$eq | Uguale (predefinito quando si usa {"field": value}) |
$ne | Diverso |
$gt / $gte | Maggiore di / maggiore o uguale a |
$lt / $lte | Minore di / minore o uguale a |
$in | Il valore è in una lista |
$nin | Il valore non è in una lista |
Update — modificare i documenti
update_one() modifica il primo documento corrispondente. update_many() modifica tutte le corrispondenze. Usa sempre l'operatore $set per modificare campi specifici — senza di esso sostituiresti l'intero documento.
# Update a single document: change the price of "Mouse"
update_result = products.update_one(
{"name": "Mouse"}, # filter
{"$set": {"price": 24.99}} # update
)
print("Matched:", update_result.matched_count,
"Modified:", update_result.modified_count)
# Mark all Acme products as in stock
products.update_many(
{"brand": "Acme"},
{"$set": {"in_stock": True}}
)
# Increment a field value
products.update_one(
{"name": "Laptop"},
{"$inc": {"price": -50}} # reduce price by 50
)Operatori di aggiornamento comuni:
| Operatore | Effetto |
|---|---|
$set | Imposta uno o più campi |
$unset | Rimuove un campo |
$inc | Incrementa un campo numerico |
$push | Aggiunge un valore a un campo array |
$pull | Rimuove un valore da un campo array |
Delete — rimuovere i documenti
delete_one() rimuove il primo documento corrispondente. delete_many() rimuove tutte le corrispondenze.
# Remove a single document
del_result = products.delete_one({"name": "Keyboard"})
print("Deleted count:", del_result.deleted_count)
# Remove all out-of-stock items
products.delete_many({"in_stock": False})
# Confirm what is left
print("Remaining products:")
for p in products.find({}, {"_id": 0, "name": 1}):
print(" -", p["name"])Errori comuni
La creazione lazy può nascondere i refusi
Poiché MongoDB crea database e collection su richiesta, un refuso crea silenziosamente un secondo database vuoto invece di generare un errore:
# Intended: client["mystore"] Actual: client["mystoree"]
db = client["mystoree"] # no error, but your data goes to the wrong databaseSoluzione: definisci i nomi di database e collection come costanti a livello di modulo:
DB_NAME = "mystore"
COL_NAME = "products"
db = client[DB_NAME]
products = db[COL_NAME]Gli errori di connessione emergono solo alla prima operazione
MongoClient() ha successo anche quando MongoDB non è in esecuzione. L'errore appare solo quando effettui una richiesta concreta. Usa serverSelectionTimeoutMS e un controllo ping all'avvio (come mostrato nella sezione sulla connessione) per rilevare i problemi il prima possibile.
L'assenza di $set sostituisce l'intero documento
# WRONG — replaces the whole document with just {"price": 24.99}
products.update_one({"name": "Mouse"}, {"price": 24.99})
# CORRECT — only changes the price field
products.update_one({"name": "Mouse"}, {"$set": {"price": 24.99}})find() restituisce un cursore, non una lista
Un cursore è lazy — i documenti vengono recuperati dal server solo mentre si itera. Se hai bisogno di una lista semplice, convertila esplicitamente:
all_products = list(products.find())Presta attenzione con le collection di grandi dimensioni: caricare tutto in memoria in una sola volta può esaurire la RAM.
Cosa c'è dopo
Questo capitolo ha trattato gli elementi essenziali. Il resto della serie Python MongoDB approfondisce ogni argomento:
- MongoDB Create Database — come funziona la creazione lazy e come verificare l'esistenza di un database.
- MongoDB Create Collection — opzioni di creazione delle collection e schemi di validazione.
- MongoDB Insert —
insert_one(),insert_many()e gestione degli errori di chiave duplicata. - MongoDB Find — proiezioni, cursori e ordinamento.
- MongoDB Query — riferimento completo degli operatori di query.
- MongoDB Update —
update_one(),update_many(),upserte operatori su array. - MongoDB Delete — pattern di eliminazione sicura e
drop(). - MongoDB Sort — ordinamento su singolo campo e su più campi.
- MongoDB Limit — paginazione con
limit()eskip(). - MongoDB Drop Collection — rimozione completa di una collection.