Insertar en MongoDB
Aprende a insertar uno o varios documentos en MongoDB usando el driver pymongo de Python, con manejo de errores, ObjectId e inserciones masivas.
MongoDB almacena los datos como documentos — objetos flexibles similares a JSON que pueden contener campos anidados y arrays. Este capítulo muestra cómo insertar un documento a la vez con insert_one(), insertar varios documentos en una sola llamada con insert_many(), comprender el campo _id generado automáticamente, gestionar errores de clave duplicada y elegir entre inserciones masivas ordenadas y no ordenadas.
Requisitos previos
- Python 3.8 o posterior instalado.
- Un servidor MongoDB en ejecución (local o remoto). Si aún no lo has configurado, consulta MongoDB: Primeros pasos.
- Una base de datos y una colección listas para usar. Consulta Crear base de datos en MongoDB y Crear colección en MongoDB si necesitas un repaso.
- El driver
pymongoinstalado:
pip install pymongoConexión a MongoDB
Importa MongoClient y abre una conexión antes de realizar cualquier operación de inserción. Cuando MongoDB se ejecuta localmente con la configuración predeterminada, puedes llamar a MongoClient() sin argumentos:
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)Para conectarte a un servidor remoto o a Atlas, pasa un URI de conexión:
client = MongoClient("mongodb://username:password@hostname:27017/")MongoClient mantiene un pool de conexiones internamente, por lo que debes crear un único cliente por aplicación y reutilizarlo en todas las operaciones.
Insertar un único documento con insert_one()
insert_one() añade un documento a una colección y devuelve un objeto InsertOneResult. La propiedad más útil de ese objeto es inserted_id, que contiene el _id asignado al nuevo 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)Ejemplo de salida:
Inserted _id: 64b3e2c1f0a1234567890abcEl valor exacto de _id será diferente cada vez — MongoDB genera un ObjectId único a menos que proporciones tu propio _id.
El campo _id
Cada documento de MongoDB debe tener un campo _id. Si no incluyes uno, el driver genera automáticamente un valor bson.ObjectId. ObjectId es un valor de 12 bytes que codifica:
- un timestamp Unix de 4 bytes (segundos),
- un valor aleatorio de 5 bytes único para la máquina y el proceso,
- un contador incremental de 3 bytes.
Esto significa que los valores ObjectId están ordenados cronológicamente de forma aproximada y son únicos a nivel global sin ninguna coordinación entre servidores.
Puedes proporcionar tu propio _id si tienes una clave única natural (por ejemplo, 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-1Si insertas un segundo documento con el mismo _id, MongoDB lanza un DuplicateKeyError (consulta Manejo de errores a continuación).
Insertar varios documentos con insert_many()
insert_many() acepta una lista de documentos y los inserta todos en un único viaje de red. Devuelve un InsertManyResult cuyo atributo inserted_ids contiene la lista de valores _id asignados en el orden de inserción.
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)Ejemplo de salida:
Inserted IDs: [ObjectId('...'), ObjectId('...'), ObjectId('...')]Inserciones ordenadas vs. no ordenadas
De forma predeterminada, insert_many() usa el modo ordenado: los documentos se insertan uno a uno en el orden de la lista, y el procesamiento se detiene en el primer error.
Pasa ordered=False para el modo no ordenado: MongoDB intenta insertar cada documento de forma independiente y acumula todos los errores antes de lanzar una excepción. Esto es más rápido para lotes grandes donde se esperan algunos duplicados y se prefiere omitir los documentos incorrectos en lugar de abortar todo el lote.
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 y Book C se insertan aunque el duplicado falle. Con ordered=True (el valor predeterminado), el procesamiento se detendría en el tercer documento y Book C nunca se insertaría.
Manejo de errores
Error de clave duplicada
Insertar un documento cuyo _id (o cualquier campo cubierto por un índice único) ya existe lanza 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"])Salida:
Duplicate key: {'_id': 'isbn-001'}Errores de conexión
MongoClient() tiene éxito incluso cuando MongoDB no está en ejecución — el error solo aparece cuando realizas una solicitud real. Envuelve las operaciones de inserción en un bloque try/except para gestionar los fallos de conexión correctamente:
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)Verificar el resultado
Tanto insert_one() como insert_many() devuelven objetos de resultado con propiedades útiles:
| Objeto de resultado | Propiedades clave |
|---|---|
InsertOneResult | inserted_id, acknowledged |
InsertManyResult | inserted_ids (lista), acknowledged |
acknowledged es True cuando MongoDB confirma la escritura. Solo puede ser False cuando se usa una confirmación de escritura no reconocida (w=0), que omite la confirmación para maximizar la velocidad a costa de no saber si la escritura tuvo éxito.
Ejemplo completo de funcionamiento
El siguiente script autocontenido se conecta a un servidor MongoDB local, inserta varios documentos e imprime los resultados:
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()Salida esperada:
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: 6Errores comunes
PyMongo modifica tu documento
Cuando pasas un dict simple a insert_one(), PyMongo añade una clave _id al dict original:
doc = {"title": "My Book"}
col.insert_one(doc)
print(doc) # {'title': 'My Book', '_id': ObjectId('...')}Si planeas reutilizar el mismo dict (por ejemplo, en un bucle), pasa una copia en su lugar: col.insert_one(doc.copy()).
Para inserciones grandes, usa insert_many() en lugar de un bucle
Insertar 10 000 documentos uno a uno genera 10 000 viajes de red. Usa insert_many() para enviarlos todos a la vez — es órdenes de magnitud más rápido para cargas masivas.
Si tu lista es muy grande (millones de documentos), divídela en lotes de algunos miles para evitar superar el límite de tamaño de documento BSON de 48 MB por lote.
Los campos de fecha necesitan objetos datetime, no cadenas de texto
MongoDB almacena las fechas como BSON Date (milisegundos desde el epoch). Usa datetime.datetime de Python para los campos de fecha para que se almacenen y consulten correctamente:
from datetime import datetime
col.insert_one({"title": "New Book", "published": datetime(2024, 3, 15)})Próximos pasos
- MongoDB Find — consulta y filtra los documentos que acabas de insertar.
- MongoDB Update — modifica documentos existentes.
- MongoDB Delete — elimina documentos de una colección.
- MongoDB Query — usa operadores de comparación y lógicos para filtrar resultados.