MongoDB Insert
Aprenda a inserir documentos únicos e múltiplos no MongoDB com Python e o driver pymongo — com tratamento de erros, ObjectId e inserção em lote.
O MongoDB armazena dados como documentos — objetos flexíveis semelhantes a JSON que podem conter campos aninhados e arrays. Este capítulo mostra como inserir um documento de cada vez com insert_one(), inserir vários documentos em uma única chamada com insert_many(), entender o campo _id gerado automaticamente, tratar erros de chave duplicada e escolher entre inserções em lote ordenadas e não ordenadas.
Pré-requisitos
- Python 3.8 ou posterior instalado.
- Um servidor MongoDB em execução (local ou remoto). Se você ainda não configurou um, consulte MongoDB Get Started.
- Um banco de dados e uma coleção prontos para uso. Consulte MongoDB Create Database e MongoDB Create Collection se precisar de uma revisão.
- O driver
pymongoinstalado:
pip install pymongoConectando ao MongoDB
Importe MongoClient e abra uma conexão antes de realizar qualquer operação de inserção. Quando o MongoDB estiver em execução localmente com as configurações padrão, você pode chamar MongoClient() sem 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 conectar a um servidor remoto ou ao Atlas, passe uma URI de conexão:
client = MongoClient("mongodb://username:password@hostname:27017/")MongoClient mantém um pool de conexões internamente, portanto você deve criar um cliente por aplicação e reutilizá-lo em todas as operações.
Inserindo um Único Documento com insert_one()
insert_one() adiciona um documento a uma coleção e retorna um objeto InsertOneResult. A propriedade mais útil desse objeto é inserted_id, que contém o _id atribuído ao novo 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)Exemplo de saída:
Inserted _id: 64b3e2c1f0a1234567890abcO valor exato de _id será diferente a cada vez — o MongoDB gera um ObjectId único a menos que você forneça o seu próprio _id.
Entendendo o Campo _id
Todo documento MongoDB deve ter um campo _id. Se você não incluir um, o driver gera automaticamente um valor bson.ObjectId. O ObjectId é um valor de 12 bytes que codifica:
- um timestamp Unix de 4 bytes (segundos),
- um valor aleatório de 5 bytes exclusivo para a máquina e o processo,
- um contador incremental de 3 bytes.
Isso significa que os valores de ObjectId são aproximadamente ordenados cronologicamente e globalmente únicos sem nenhuma coordenação entre servidores.
Você pode fornecer seu próprio _id se tiver uma chave única natural (por exemplo, um 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 você inserir um segundo documento com o mesmo _id, o MongoDB lança um DuplicateKeyError (consulte Tratando Erros abaixo).
Inserindo Vários Documentos com insert_many()
insert_many() aceita uma lista de documentos e os insere todos em uma única viagem de rede. Ele retorna um InsertManyResult cujo atributo inserted_ids contém a lista de valores _id atribuídos na ordem de inserção.
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)Exemplo de saída:
Inserted IDs: [ObjectId('...'), ObjectId('...'), ObjectId('...')]Inserções Ordenadas vs. Não Ordenadas
Por padrão, insert_many() usa o modo ordenado: os documentos são inseridos um a um na ordem da lista, e o processamento para no primeiro erro.
Passe ordered=False para o modo não ordenado: o MongoDB tenta cada documento de forma independente e coleta todos os erros antes de lançar uma exceção. Isso é mais rápido para grandes lotes onde você espera algumas duplicatas e deseja ignorar documentos inválidos em vez de abortar todo o 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"])Com ordered=False, Book A, Book B e Book C são inseridos mesmo que a duplicata falhe. Com ordered=True (padrão), o processamento pararia no terceiro documento e Book C nunca seria inserido.
Tratando Erros
Erro de Chave Duplicada
Inserir um documento cujo _id (ou qualquer campo coberto por um índice único) já existe lança 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"])Saída:
Duplicate key: {'_id': 'isbn-001'}Erros de Conexão
MongoClient() tem sucesso mesmo quando o MongoDB não está em execução — o erro só aparece quando você faz uma solicitação real. Envolva as operações de inserção em um try/except para tratar falhas de conexão de forma 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)Verificando o Resultado
Tanto insert_one() quanto insert_many() retornam objetos de resultado com propriedades úteis:
| Objeto de resultado | Propriedades principais |
|---|---|
InsertOneResult | inserted_id, acknowledged |
InsertManyResult | inserted_ids (lista), acknowledged |
acknowledged é True quando o MongoDB confirmou a escrita. Pode ser False somente quando você usa um nível de escrita não reconhecida (w=0), que ignora a confirmação para máxima velocidade ao custo de não saber se a escrita foi bem-sucedida.
Exemplo Completo Funcional
O script autocontido a seguir conecta a um servidor MongoDB local, insere vários documentos e imprime os 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()Saída 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: 6Erros Comuns
PyMongo modifica seu documento
Quando você passa um dict simples para insert_one(), o PyMongo adiciona uma chave _id ao dict original:
doc = {"title": "My Book"}
col.insert_one(doc)
print(doc) # {'title': 'My Book', '_id': ObjectId('...')}Se você planeja reutilizar o mesmo dict (por exemplo, em um loop), passe uma cópia: col.insert_one(doc.copy()).
Inserções grandes: use insert_many() e não um loop
Inserir 10.000 documentos um a um realiza 10.000 viagens de rede. Use insert_many() para enviá-los todos de uma vez — é ordens de magnitude mais rápido para cargas em lote.
Se sua lista for muito grande (milhões de documentos), divida-a em lotes de alguns milhares para evitar exceder o limite de tamanho de documento BSON de 48 MB por lote.
Campos de data precisam de objetos datetime, não strings
O MongoDB armazena datas como BSON Date (milissegundos desde a época). Use datetime.datetime do Python para campos de data para que sejam armazenados e consultados corretamente:
from datetime import datetime
col.insert_one({"title": "New Book", "published": datetime(2024, 3, 15)})Próximos Passos
- MongoDB Find — consulte e filtre os documentos que você acabou de inserir.
- MongoDB Update — modifique documentos existentes.
- MongoDB Delete — remova documentos de uma coleção.
- MongoDB Query — use operadores de comparação e lógicos para filtrar resultados.