MongoDB com Python e PyMongo: guia prático
Conecte Python ao MongoDB e domine operações CRUD com PyMongo. Do insert ao aggregate.
O que é o MongoDB?
O MongoDB é um banco de dados NoSQL orientado a documentos. Em vez de tabelas com linhas e colunas, ele armazena dados como documentos JSON (internamente BSON). Cada documento pode ter uma estrutura diferente, o que dá flexibilidade enorme para modelar dados.
| Conceito SQL | Equivalente MongoDB |
|---|---|
| Tabela | Coleção (collection) |
| Linha | Documento (document) |
| Coluna | Campo (field) |
| JOIN | Embedding / Lookup |
Um documento se parece com um dicionário Python:
{
"_id": "664f1a2b3c4d5e6f7a8b9c0d",
"titulo": "Aprender MongoDB",
"autor": "Ana Silva",
"tags": ["python", "nosql"],
"publicado": True,
"visualizacoes": 1250
}
O campo tags é uma lista dentro do documento. Você pode aninhar listas, subdocumentos e qualquer estrutura que um JSON suporta.
Instalação e conexão
Instale o PyMongo (driver oficial) com pip:
pip install pymongo
Para rodar o MongoDB, use Docker, instale localmente ou crie um cluster gratuito no MongoDB Atlas.
Conexão local
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017/")
db = client["meu_blog"]
posts = db["posts"]
Conexão ao Atlas
pip install "pymongo[srv]"
uri = "mongodb+srv://usuario:senha@cluster0.xxxxx.mongodb.net/"
client = MongoClient(uri)
db = client["meu_blog"]
Se a coleção não existir, o MongoDB a cria automaticamente ao inserir o primeiro documento.
Create: inserindo documentos
posts = db["posts"]
# Inserir um documento
resultado = posts.insert_one({
"titulo": "Introducao ao MongoDB",
"autor": "Carlos Lima",
"tags": ["mongodb", "nosql"],
"publicado": True,
"visualizacoes": 0
})
print(f"ID gerado: {resultado.inserted_id}")
# Inserir varios documentos
varios = [
{"titulo": "Python para iniciantes", "autor": "Ana Silva",
"tags": ["python"], "publicado": True, "visualizacoes": 3200},
{"titulo": "Flask vs Django", "autor": "Carlos Lima",
"tags": ["python", "web"], "publicado": True, "visualizacoes": 1850},
{"titulo": "Redis na pratica", "autor": "Julia Santos",
"tags": ["redis", "cache"], "publicado": False, "visualizacoes": 0},
]
resultado = posts.insert_many(varios)
print(f"{len(resultado.inserted_ids)} posts inseridos")
Read: buscando documentos
# Buscar um documento
post = posts.find_one({"titulo": "Introducao ao MongoDB"})
# Buscar pelo _id
from bson.objectid import ObjectId
post = posts.find_one({"_id": ObjectId("664f1a2b3c4d5e6f7a8b9c0d")})
# Buscar varios (retorna um cursor iteravel)
publicados = posts.find({"publicado": True})
for post in publicados:
print(f"{post['titulo']} - {post['visualizacoes']} views")
Filtros com operadores
# Visualizacoes maiores que 1000
posts.find({"visualizacoes": {"$gt": 1000}})
# Entre 500 e 2000
posts.find({"visualizacoes": {"$gte": 500, "$lte": 2000}})
# Autor e Ana OU Julia
posts.find({"autor": {"$in": ["Ana Silva", "Julia Santos"]}})
# Posts com a tag "python"
posts.find({"tags": "python"})
| Operador | Significado | Exemplo |
|---|---|---|
$gt |
Maior que | {"idade": {"$gt": 18}} |
$gte |
Maior ou igual | {"nota": {"$gte": 7.0}} |
$lt |
Menor que | {"preco": {"$lt": 100}} |
$lte |
Menor ou igual | {"estoque": {"$lte": 5}} |
$ne |
Diferente de | {"status": {"$ne": "inativo"}} |
$in |
Está na lista | {"cor": {"$in": ["azul"]}} |
$exists |
Campo existe | {"email": {"$exists": True}} |
$regex |
Expressão regular | {"nome": {"$regex": "^Ana"}} |
Projeções e ordenação
# Retornar apenas titulo e autor
posts.find({"publicado": True}, {"titulo": 1, "autor": 1, "_id": 0})
# Ordenar por visualizacoes (decrescente) e limitar
from pymongo import DESCENDING
top_3 = posts.find().sort("visualizacoes", DESCENDING).limit(3)
# Contar documentos
total = posts.count_documents({"publicado": True})
Update: atualizando documentos
# Atualizar um campo com $set
posts.update_one(
{"titulo": "Introducao ao MongoDB"},
{"$set": {"visualizacoes": 150}}
)
# Incrementar um valor com $inc
posts.update_one(
{"titulo": "Introducao ao MongoDB"},
{"$inc": {"visualizacoes": 1}}
)
# Adicionar a uma lista com $push
posts.update_one(
{"titulo": "Introducao ao MongoDB"},
{"$push": {"tags": "banco-de-dados"}}
)
# Atualizar varios documentos
resultado = posts.update_many(
{"autor": "Julia Santos"},
{"$set": {"publicado": True}}
)
print(f"{resultado.modified_count} post(s) atualizado(s)")
Delete: removendo documentos
posts.delete_one({"titulo": "Redis na pratica"})
resultado = posts.delete_many({"publicado": False})
print(f"{resultado.deleted_count} rascunho(s) removido(s)")
Aggregation Pipeline
O aggregation pipeline é o recurso mais poderoso do MongoDB para análise de dados. Cada estágio recebe documentos, processa e passa para o próximo.
# Contar posts por autor
pipeline = [
{"$group": {
"_id": "$autor",
"total_posts": {"$sum": 1},
"media_views": {"$avg": "$visualizacoes"}
}},
{"$sort": {"total_posts": -1}}
]
for r in posts.aggregate(pipeline):
print(f"{r['_id']}: {r['total_posts']} posts, media {r['media_views']:.0f} views")
# Top tags mais usadas
pipeline = [
{"$unwind": "$tags"},
{"$group": {"_id": "$tags", "contagem": {"$sum": 1}}},
{"$sort": {"contagem": -1}},
{"$limit": 5}
]
for tag in posts.aggregate(pipeline):
print(f"#{tag['_id']}: {tag['contagem']} usos")
| Estágio | Função |
|---|---|
$match |
Filtrar documentos (como WHERE no SQL) |
$group |
Agrupar e calcular (como GROUP BY) |
$sort |
Ordenar resultados |
$limit |
Limitar quantidade de resultados |
$project |
Escolher e renomear campos |
$unwind |
Desmembrar arrays em documentos individuais |
$lookup |
JOIN com outra coleção |
Índices
Índices aceleram consultas. Sem eles, o MongoDB percorre todos os documentos da coleção.
posts.create_index("titulo") # indice simples
posts.create_index("titulo", unique=True) # indice unico
posts.create_index([("autor", 1), ("visualizacoes", -1)]) # composto
# Indice de texto para busca textual
posts.create_index([("titulo", "text"), ("conteudo", "text")])
resultados = posts.find({"$text": {"$search": "MongoDB Python"}})
Crie índices nos campos usados com frequência em filtros e ordenações. Evite criar índices em todos os campos — eles ocupam espaço e tornam escritas mais lentas.
Exemplo prático: catálogo de produtos
from pymongo import MongoClient, DESCENDING
client = MongoClient("mongodb://localhost:27017/")
db = client["loja"]
produtos = db["produtos"]
# Inserir catalogo
produtos.delete_many({})
produtos.insert_many([
{"nome": "Notebook Pro", "categoria": "eletronicos",
"preco": 4599.90, "estoque": 23, "avaliacao": 4.5},
{"nome": "Mouse Gamer", "categoria": "perifericos",
"preco": 189.90, "estoque": 150, "avaliacao": 4.2},
{"nome": "Monitor 4K", "categoria": "perifericos",
"preco": 2199.90, "estoque": 35, "avaliacao": 4.7},
{"nome": "Teclado Mecanico", "categoria": "perifericos",
"preco": 349.90, "estoque": 80, "avaliacao": 4.3},
{"nome": "SSD 1TB NVMe", "categoria": "armazenamento",
"preco": 459.90, "estoque": 200, "avaliacao": 4.8},
])
# Buscar por faixa de preco
for p in produtos.find({"preco": {"$gte": 100, "$lte": 500}}).sort("preco", DESCENDING):
print(f" {p['nome']}: R${p['preco']:.2f}")
# Estatisticas por categoria
pipeline = [
{"$group": {
"_id": "$categoria",
"total": {"$sum": 1},
"preco_medio": {"$avg": "$preco"},
"estoque_total": {"$sum": "$estoque"}
}},
{"$sort": {"preco_medio": -1}}
]
print("\nEstatisticas por categoria:")
for r in produtos.aggregate(pipeline):
print(f" {r['_id']}: {r['total']} produtos, media R${r['preco_medio']:.2f}")
Próximos passos
Com PyMongo você tem acesso completo ao MongoDB a partir do Python. Para evoluir, explore o Motor (driver assíncrono para asyncio), aprenda a modelar dados com embedding vs referencing e estude padrões de índices para otimizar consultas. Se estiver usando Flask ou FastAPI, combine o MongoDB com essas frameworks para criar APIs completas.