Consultas MongoDB em Python: Filtros, Operadores e Projeção
Aprenda a consultar o MongoDB com Python e pymongo — filtre documentos, use operadores de comparação e lógicos, projete campos e pagine resultados.
Este capítulo explica como construir consultas no MongoDB usando o driver pymongo do Python. Você aprenderá a filtrar documentos com correspondências exatas e operadores de comparação, combinar condições com operadores lógicos, selecionar apenas os campos necessários com projeção, e paginar resultados com skip() e limit().
Se você ainda não configurou uma conexão, consulte MongoDB Get Started e MongoDB Create Collection primeiro.
Configuração dos Dados de Exemplo
Todos os exemplos deste capítulo utilizam a mesma coleção customers. Execute este trecho uma vez para populá-la:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mystore"]
col = db["customers"]
# Drop and re-create so examples are repeatable
col.drop()
col.insert_many([
{"name": "Alice", "age": 30, "city": "London", "score": 88},
{"name": "Bob", "age": 25, "city": "New York", "score": 74},
{"name": "Carol", "age": 35, "city": "London", "score": 91},
{"name": "Dave", "age": 28, "city": "Berlin", "score": 65},
{"name": "Eve", "age": 22, "city": "New York", "score": 77},
])
print("Sample data inserted.")Consultando Todos os Documentos
Chamar find() com um filtro vazio ({}) retorna todos os documentos da coleção:
for doc in col.find({}):
print(doc)
# {'_id': ..., 'name': 'Alice', 'age': 30, 'city': 'London', 'score': 88}
# {'_id': ..., 'name': 'Bob', 'age': 25, 'city': 'New York', 'score': 74}
# ...Use find_one() quando precisar apenas do primeiro documento correspondente:
doc = col.find_one({"city": "London"})
print(doc)
# {'_id': ..., 'name': 'Alice', 'age': 30, 'city': 'London', 'score': 88}find_one() retorna None se nenhum documento corresponder — verifique sempre isso antes de acessar os campos.
Filtros de Correspondência Exata
Passe um dicionário para find() para corresponder documentos em que um campo seja igual a um valor específico:
# All customers in London
results = col.find({"city": "London"})
for doc in results:
print(doc["name"], doc["city"])
# Alice London
# Carol LondonMúltiplas chaves no mesmo dicionário de filtro funcionam como um AND implícito — ambas as condições devem ser verdadeiras:
# Customers in London AND older than 30
results = col.find({"city": "London", "age": {"$gt": 30}})
for doc in results:
print(doc["name"], doc["age"])
# Carol 35Operadores de Comparação
Os operadores de comparação do MongoDB permitem corresponder documentos em que um campo esteja dentro de um intervalo ou conjunto. Todos os operadores são prefixados com $.
| Operador | Significado | Exemplo de filtro |
|---|---|---|
$eq | Igual a | {"age": {"$eq": 30}} |
$ne | Diferente de | {"city": {"$ne": "London"}} |
$gt | Maior que | {"score": {"$gt": 80}} |
$gte | Maior ou igual a | {"score": {"$gte": 80}} |
$lt | Menor que | {"age": {"$lt": 28}} |
$lte | Menor ou igual a | {"age": {"$lte": 28}} |
$in | Em uma lista | {"city": {"$in": ["London", "Berlin"]}} |
$nin | Não está em uma lista | {"city": {"$nin": ["London"]}} |
Exemplo — clientes com pontuação acima de 80:
results = col.find({"score": {"$gt": 80}})
for doc in results:
print(doc["name"], doc["score"])
# Alice 88
# Carol 91Exemplo — clientes com idade entre 25 e 30 (inclusive):
results = col.find({"age": {"$gte": 25, "$lte": 30}})
for doc in results:
print(doc["name"], doc["age"])
# Alice 30
# Bob 25
# Dave 28Você pode empilhar múltiplos operadores no mesmo campo dentro de um único dicionário, como mostrado acima.
Exemplo — clientes em Londres ou Berlim:
results = col.find({"city": {"$in": ["London", "Berlin"]}})
for doc in results:
print(doc["name"], doc["city"])
# Alice London
# Carol London
# Dave BerlinOperadores Lógicos
Use $and, $or e $nor quando precisar combinar condições de maneiras que as chaves simples de dicionário não conseguem expressar.
$or — pelo menos uma condição deve corresponder
# Customers younger than 25 OR with a score above 90
results = col.find({"$or": [{"age": {"$lt": 25}}, {"score": {"$gt": 90}}]})
for doc in results:
print(doc["name"], doc["age"], doc["score"])
# Carol 35 91
# Eve 22 77$and — use ao aplicar dois operadores diferentes ao mesmo campo
O AND implícito (múltiplas chaves) não funciona quando você precisa de dois operadores $ no mesmo campo. Use $and em vez disso:
# Customers whose score is > 65 AND < 90
# (cannot use {"score": {"$gt": 65}, "score": {"$lt": 90}} — duplicate key)
results = col.find({"$and": [{"score": {"$gt": 65}}, {"score": {"$lt": 90}}]})
for doc in results:
print(doc["name"], doc["score"])
# Alice 88
# Bob 74
# Eve 77$nor — nenhuma das condições deve corresponder
# Customers who are NOT in London AND do NOT have score > 80
results = col.find({"$nor": [{"city": "London"}, {"score": {"$gt": 80}}]})
for doc in results:
print(doc["name"], doc["city"], doc["score"])
# Bob New York 74
# Dave Berlin 65
# Eve New York 77$not — negar uma expressão de campo único
$not envolve uma única expressão de operador e retorna documentos em que a condição é falsa ou o campo não existe:
# Customers who do NOT have a score greater than 80
results = col.find({"score": {"$not": {"$gt": 80}}})
for doc in results:
print(doc["name"], doc["score"])
# Bob 74
# Dave 65
# Eve 77Filtros com Expressões Regulares
Use o operador $regex (ou passe um padrão re compilado) para fazer correspondência de substring ou padrão em campos string:
import re
# Customers whose name starts with a vowel
results = col.find({"name": {"$regex": "^[AEIOU]", "$options": "i"}})
for doc in results:
print(doc["name"])
# Alice
# Eve$options: "i" torna a correspondência insensível a maiúsculas e minúsculas. Evite padrões com curinga no início, como .*text, em coleções grandes — eles não podem usar um índice e realizarão uma varredura completa da coleção.
Projeção — Retornando Apenas Campos Específicos
Por padrão, find() retorna todos os campos do documento, incluindo _id. Use um segundo argumento (a projeção) para incluir ou excluir campos.
Incluir campos específicos
Passe 1 para cada campo desejado. Somente esses campos (mais _id) são retornados:
# Return only name and score
results = col.find({}, {"name": 1, "score": 1})
for doc in results:
print(doc)
# {'_id': ..., 'name': 'Alice', 'score': 88}
# {'_id': ..., 'name': 'Bob', 'score': 74}
# ...Excluir campos específicos
Passe 0 para cada campo que deseja ocultar. Todos os outros campos são retornados:
# Hide _id and city
results = col.find({}, {"_id": 0, "city": 0})
for doc in results:
print(doc)
# {'name': 'Alice', 'age': 30, 'score': 88}
# {'name': 'Bob', 'age': 25, 'score': 74}
# ...Você não pode misturar 1 e 0 na mesma projeção (exceto para _id, que sempre pode ser definido como 0 junto com inclusões).
Ordenando Resultados
Encadeie .sort() no cursor para ordenar os resultados. Use pymongo.ASCENDING (1) ou pymongo.DESCENDING (-1):
import pymongo
# Sort by score descending
results = col.find({}, {"_id": 0, "name": 1, "score": 1}).sort("score", pymongo.DESCENDING)
for doc in results:
print(doc["name"], doc["score"])
# Carol 91
# Alice 88
# Eve 77
# Bob 74
# Dave 65Passe uma lista de tuplas (campo, direção) para ordenar por múltiplos campos:
# Sort by city ascending, then by age descending within each city
results = col.find({}, {"_id": 0, "name": 1, "city": 1, "age": 1}).sort(
[("city", pymongo.ASCENDING), ("age", pymongo.DESCENDING)]
)
for doc in results:
print(doc["city"], doc["name"], doc["age"])
# Berlin Dave 28
# London Carol 35
# London Alice 30
# New York Bob 25 <- Bob (25) vs Eve (22): descending so 25 first
# New York Eve 22Consulte MongoDB Sort para uma análise mais aprofundada das opções de ordenação.
Limitando e Paginando Resultados
limit()
limit(n) interrompe o cursor após retornar n documentos:
# Top 3 by score
results = col.find({}, {"_id": 0, "name": 1, "score": 1}).sort("score", -1).limit(3)
for doc in results:
print(doc["name"], doc["score"])
# Carol 91
# Alice 88
# Eve 77skip() para paginação
Combine skip() e limit() para implementar uma navegação simples página a página:
page_size = 2
page = 1 # zero-indexed
results = (
col.find({}, {"_id": 0, "name": 1, "score": 1})
.sort("score", -1)
.skip(page * page_size)
.limit(page_size)
)
for doc in results:
print(doc["name"], doc["score"])
# Eve 77 (page 1, items 3–4 of the sorted list)
# Bob 74Para coleções grandes, prefira a paginação baseada em intervalo — filtre pelo último _id visto ou por um timestamp — porque skip() ainda varre os documentos ignorados internamente.
Consulte MongoDB Limit para mais detalhes.
Contando Documentos
Use count_documents() com o mesmo dicionário de filtro para contar sem buscar dados:
total = col.count_documents({})
london = col.count_documents({"city": "London"})
print(f"Total: {total}, In London: {london}")
# Total: 5, In London: 2Evite o cursor.count() obsoleto — ele foi removido no PyMongo 4.
Armadilhas Comuns
Os cursores do PyMongo são esgotados após a iteração. Uma vez que você percorre um cursor, ele fica vazio. Armazene os resultados em uma lista se precisar iterar mais de uma vez:
docs = list(col.find({"city": "London"}))
print(len(docs)) # 2
print(docs[0]["name"]) # Alice_id é um ObjectId, não uma string. Se você armazenar um _id como string e depois tentar consultá-lo, a consulta não retornará nada. Importe ObjectId de bson para converter:
from bson import ObjectId
doc = col.find_one({"_id": ObjectId("665000000000000000000001")})As consultas diferenciam maiúsculas de minúsculas por padrão. {"city": "london"} não corresponderá a documentos armazenados como "London". Use $regex com $options: "i" para correspondência insensível a maiúsculas, ou normalize os valores no momento da inserção.
Próximos Passos
- MongoDB Find —
find()efind_one()em profundidade - MongoDB Sort — ordenação por múltiplos campos e dicas de índice
- MongoDB Limit — controle do tamanho dos resultados
- MongoDB Update — modificando documentos após localizá-los
- MongoDB Delete — removendo documentos de uma coleção