Inserimento in MongoDB
Impara a inserire singoli e multipli documenti in MongoDB con Python e pymongo — con gestione degli errori, ObjectId e opzioni di inserimento bulk.
MongoDB memorizza i dati come documenti — oggetti flessibili simili a JSON che possono contenere campi annidati e array. Questo capitolo mostra come inserire un documento alla volta con insert_one(), inserire più documenti in una singola chiamata con insert_many(), comprendere il campo _id generato automaticamente, gestire gli errori di chiave duplicata e scegliere tra inserimenti bulk ordinati e non ordinati.
Prerequisiti
- Python 3.8 o versione successiva installato.
- Un server MongoDB in esecuzione (locale o remoto). Se non ne hai ancora configurato uno, consulta MongoDB Get Started.
- Un database e una collection pronti all'uso. Consulta MongoDB Create Database e MongoDB Create Collection se hai bisogno di un ripasso.
- Il driver
pymongoinstallato:
pip install pymongoConnessione a MongoDB
Importa MongoClient e apri una connessione prima di eseguire qualsiasi operazione di inserimento. Quando MongoDB è in esecuzione localmente con le impostazioni predefinite, puoi chiamare MongoClient() senza argomenti:
from pymongo import MongoClient
client = MongoClient() # connects to localhost:27017
db = client["bookstore"] # database (created on first write)
books = db["books"] # collection (created on first write)Per connettersi a un server remoto o ad Atlas, passa un URI di connessione:
client = MongoClient("mongodb://username:password@hostname:27017/")MongoClient mantiene internamente un pool di connessioni, quindi dovresti creare un solo client per applicazione e riutilizzarlo in tutte le operazioni.
Inserimento di un singolo documento con insert_one()
insert_one() aggiunge un documento a una collection e restituisce un object InsertOneResult. La proprietà più utile di quell'object è inserted_id, che contiene il valore _id assegnato al nuovo documento.
from pymongo import MongoClient
client = MongoClient()
books = client["bookstore"]["books"]
document = {
"title": "The Pragmatic Programmer",
"author": "David Thomas",
"year": 1999,
"in_stock": True,
}
result = books.insert_one(document)
print("Inserted _id:", result.inserted_id)Output di esempio:
Inserted _id: 64b3e2c1f0a1234567890abcIl valore esatto di _id sarà diverso ogni volta — MongoDB genera un ObjectId univoco a meno che tu non ne fornisca uno personale.
Il campo _id
Ogni documento MongoDB deve avere un campo _id. Se non ne includi uno, il driver genera automaticamente un valore bson.ObjectId. ObjectId è un valore di 12 byte che codifica:
- un timestamp Unix a 4 byte (secondi),
- un valore casuale a 5 byte univoco per la macchina e il processo,
- un contatore incrementale a 3 byte.
Ciò significa che i valori ObjectId sono approssimativamente ordinati in ordine cronologico e globalmente unici senza alcun coordinamento tra i server.
Puoi fornire il tuo _id se hai una chiave univoca naturale (ad esempio, un ISBN):
result = books.insert_one({
"_id": "978-0-13-468599-1",
"title": "The Pragmatic Programmer",
"author": "David Thomas",
"year": 1999,
})
print("Inserted _id:", result.inserted_id)
# Inserted _id: 978-0-13-468599-1Se inserisci un secondo documento con lo stesso _id, MongoDB genera un DuplicateKeyError (vedi Gestione degli errori di seguito).
Inserimento di più documenti con insert_many()
insert_many() accetta una lista di documenti e li inserisce tutti in un singolo round-trip di rete. Restituisce un InsertManyResult il cui attributo inserted_ids contiene la lista dei valori _id assegnati nell'ordine di inserimento.
from pymongo import MongoClient
client = MongoClient()
books = client["bookstore"]["books"]
new_books = [
{"title": "Clean Code", "author": "Robert C. Martin", "year": 2008},
{"title": "Refactoring", "author": "Martin Fowler", "year": 1999},
{"title": "Design Patterns", "author": "Gang of Four", "year": 1994},
]
result = books.insert_many(new_books)
print("Inserted IDs:", result.inserted_ids)Output di esempio:
Inserted IDs: [ObjectId('...'), ObjectId('...'), ObjectId('...')]Inserimenti ordinati e non ordinati
Per impostazione predefinita, insert_many() usa la modalità ordinata: i documenti vengono inseriti uno alla volta nell'ordine della lista e l'elaborazione si interrompe al primo errore.
Passa ordered=False per la modalità non ordinata: MongoDB tenta ogni documento in modo indipendente e raccoglie tutti gli errori prima di generare un'eccezione. Questo è più veloce per batch di grandi dimensioni in cui si prevedono alcuni duplicati e si vogliono saltare i documenti problematici invece di interrompere l'intero batch.
from pymongo import MongoClient
from pymongo.errors import BulkWriteError
client = MongoClient()
books = client["bookstore"]["books"]
# Two documents with duplicate _id values mixed in
docs = [
{"_id": 1, "title": "Book A"},
{"_id": 2, "title": "Book B"},
{"_id": 1, "title": "Duplicate — will fail"}, # duplicate _id
{"_id": 3, "title": "Book C"},
]
try:
result = books.insert_many(docs, ordered=False)
print("Inserted:", result.inserted_ids)
except BulkWriteError as e:
# inserted_ids still shows the documents that succeeded
print("Some inserts failed:", e.details["nInserted"], "succeeded")
for err in e.details["writeErrors"]:
print(" Error on index", err["index"], "—", err["errmsg"])Con ordered=False, Book A, Book B e Book C vengono inseriti anche se il duplicato fallisce. Con ordered=True (il valore predefinito), l'elaborazione si fermerebbe al terzo documento e Book C non verrebbe mai inserito.
Gestione degli errori
Errore di chiave duplicata
L'inserimento di un documento il cui _id (o qualsiasi campo coperto da un indice univoco) esiste già genera pymongo.errors.DuplicateKeyError:
from pymongo import MongoClient
from pymongo.errors import DuplicateKeyError
client = MongoClient()
books = client["bookstore"]["books"]
try:
books.insert_one({"_id": "isbn-001", "title": "First"})
books.insert_one({"_id": "isbn-001", "title": "Duplicate"}) # raises
except DuplicateKeyError as e:
print("Duplicate key:", e.details["keyValue"])Output:
Duplicate key: {'_id': 'isbn-001'}Errori di connessione
MongoClient() ha successo anche quando MongoDB non è in esecuzione — l'errore emerge solo quando effettui una richiesta reale. Racchiudi le operazioni di inserimento in un blocco try/except per gestire gli errori di connessione in modo elegante:
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure, PyMongoError
client = MongoClient(serverSelectionTimeoutMS=3000)
try:
result = books.insert_one({"title": "Test"})
print("Inserted:", result.inserted_id)
except ConnectionFailure:
print("Could not reach MongoDB server.")
except PyMongoError as e:
print("MongoDB error:", e)Verifica del risultato
Sia insert_one() che insert_many() restituiscono object risultato con proprietà utili:
| Object risultato | Proprietà principali |
|---|---|
InsertOneResult | inserted_id, acknowledged |
InsertManyResult | inserted_ids (lista), acknowledged |
acknowledged è True quando MongoDB ha confermato la scrittura. Può essere False solo quando si usa una write concern non riconosciuta (w=0), che salta la conferma per ottenere la massima velocità al costo di non sapere se la scrittura è riuscita.
Esempio completo funzionante
Il seguente script autonomo si connette a un server MongoDB locale, inserisce diversi documenti e stampa i risultati:
from pymongo import MongoClient
from pymongo.errors import DuplicateKeyError, BulkWriteError
DB_NAME = "demo_bookstore"
COL_NAME = "books"
def main():
client = MongoClient(serverSelectionTimeoutMS=3000)
# Verify connectivity
client.admin.command("ping")
print("Connected to MongoDB")
col = client[DB_NAME][COL_NAME]
col.drop() # start fresh for this demo
# --- insert_one ---
result = col.insert_one({
"_id": "isbn-001",
"title": "The Pragmatic Programmer",
"author": "David Thomas",
"year": 1999,
})
print("insert_one _id:", result.inserted_id)
# --- insert_many ---
result = col.insert_many([
{"title": "Clean Code", "author": "Robert C. Martin", "year": 2008},
{"title": "Refactoring", "author": "Martin Fowler", "year": 1999},
{"title": "Design Patterns", "author": "Gang of Four", "year": 1994},
])
print("insert_many IDs:", result.inserted_ids)
# --- duplicate key ---
try:
col.insert_one({"_id": "isbn-001", "title": "Duplicate"})
except DuplicateKeyError:
print("Caught DuplicateKeyError as expected")
# --- unordered bulk insert ---
docs = [
{"_id": "isbn-002", "title": "Book A"},
{"_id": "isbn-001", "title": "Dup — will fail"}, # duplicate
{"_id": "isbn-003", "title": "Book C"},
]
try:
col.insert_many(docs, ordered=False)
except BulkWriteError as e:
print("Bulk insert: succeeded =", e.details["nInserted"],
", failed =", len(e.details["writeErrors"]))
print("Total documents:", col.count_documents({}))
# Clean up
client.drop_database(DB_NAME)
if __name__ == "__main__":
main()Output atteso:
Connected to MongoDB
insert_one _id: isbn-001
insert_many IDs: [ObjectId('...'), ObjectId('...'), ObjectId('...')]
Caught DuplicateKeyError as expected
Bulk insert: succeeded = 2 , failed = 1
Total documents: 6Problemi comuni
PyMongo modifica il tuo documento
Quando passi un dict semplice a insert_one(), PyMongo aggiunge una chiave _id al dict originale:
doc = {"title": "My Book"}
col.insert_one(doc)
print(doc) # {'title': 'My Book', '_id': ObjectId('...')}Se prevedi di riutilizzare lo stesso dict (ad esempio in un ciclo), passa invece una copia: col.insert_one(doc.copy()).
Inserimenti di grandi dimensioni: usa insert_many() invece di un ciclo
Inserire 10.000 documenti uno alla volta richiede 10.000 round-trip di rete. Usa insert_many() per inviarli tutti in una volta — è di ordini di grandezza più veloce per i caricamenti bulk.
Se la tua lista è molto grande (milioni di documenti), dividila in batch di qualche migliaio per evitare di superare il limite di dimensione del documento BSON di 48 MB per batch.
I campi datetime richiedono object datetime, non stringhe
MongoDB memorizza le date come BSON Date (millisecondi dall'epoch). Usa il tipo datetime.datetime di Python per i campi data in modo che vengano memorizzati e interrogati correttamente:
from datetime import datetime
col.insert_one({"title": "New Book", "published": datetime(2024, 3, 15)})Prossimi passi
- MongoDB Find — interroga e filtra i documenti appena inseriti.
- MongoDB Update — modifica i documenti esistenti.
- MongoDB Delete — rimuovi documenti da una collection.
- MongoDB Query — usa operatori di confronto e logici per filtrare i risultati.