W3docs

Consultas MongoDB en Python: Filtros, Operadores y Proyección

Aprende a consultar MongoDB con Python y pymongo: filtra documentos, usa operadores de comparación y lógicos, proyecta campos y pagina resultados.

Este capítulo explica cómo construir consultas en MongoDB usando el driver pymongo de Python. Aprenderás a filtrar documentos con coincidencias exactas y operadores de comparación, combinar condiciones con operadores lógicos, seleccionar solo los campos que necesitas con proyección y paginar resultados con skip() y limit().

Si aún no has configurado una conexión, consulta primero MongoDB Get Started y MongoDB Create Collection.

Configuración de Datos de Muestra

Todos los ejemplos de este capítulo usan la misma colección customers. Ejecuta este fragmento una vez para poblarla:

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.")

Consultar Todos los Documentos

Llamar a find() con un filtro vacío ({}) devuelve todos los documentos de la colección:

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}
# ...

Usa find_one() cuando solo necesites el primer documento que coincida:

doc = col.find_one({"city": "London"})
print(doc)
# {'_id': ..., 'name': 'Alice', 'age': 30, 'city': 'London', 'score': 88}

find_one() devuelve None si ningún documento coincide — comprueba siempre esto antes de acceder a los campos.

Filtros de Coincidencia Exacta

Pasa un diccionario a find() para hacer coincidir documentos donde un campo es igual a un valor específico:

# All customers in London
results = col.find({"city": "London"})
for doc in results:
    print(doc["name"], doc["city"])
# Alice London
# Carol London

Múltiples claves en el mismo diccionario de filtro actúan como un AND implícito — ambas condiciones deben ser verdaderas:

# 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 35

Operadores de Comparación

Los operadores de comparación de MongoDB permiten hacer coincidir documentos donde un campo está dentro de un rango o conjunto. Todos los operadores tienen el prefijo $.

OperadorSignificadoEjemplo de filtro
$eqIgual a{"age": {"$eq": 30}}
$neDistinto de{"city": {"$ne": "London"}}
$gtMayor que{"score": {"$gt": 80}}
$gteMayor o igual{"score": {"$gte": 80}}
$ltMenor que{"age": {"$lt": 28}}
$lteMenor o igual{"age": {"$lte": 28}}
$inEn una lista{"city": {"$in": ["London", "Berlin"]}}
$ninNo en una lista{"city": {"$nin": ["London"]}}

Ejemplo — clientes con una puntuación superior a 80:

results = col.find({"score": {"$gt": 80}})
for doc in results:
    print(doc["name"], doc["score"])
# Alice 88
# Carol 91

Ejemplo — clientes con edad entre 25 y 30 (inclusive):

results = col.find({"age": {"$gte": 25, "$lte": 30}})
for doc in results:
    print(doc["name"], doc["age"])
# Alice 30
# Bob   25
# Dave  28

Puedes combinar varios operadores sobre el mismo campo dentro de un único diccionario, como se muestra arriba.

Ejemplo — clientes en Londres o Berlín:

results = col.find({"city": {"$in": ["London", "Berlin"]}})
for doc in results:
    print(doc["name"], doc["city"])
# Alice London
# Carol London
# Dave  Berlin

Operadores Lógicos

Usa $and, $or y $nor cuando necesites combinar condiciones de formas que las claves de diccionario simples no permiten expresar.

$or — al menos una condición debe cumplirse

# 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 — úsalo cuando apliques dos operadores distintos al mismo campo

El AND implícito (múltiples claves) no funciona cuando necesitas dos operadores $ sobre el mismo campo. Usa $and en su lugar:

# 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 — ninguna de las condiciones debe cumplirse

# 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 una expresión de campo individual

$not envuelve una expresión de operador individual y devuelve los documentos donde la condición es falsa o el campo no 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  77

Filtros con Expresiones Regulares

Usa el operador $regex (o pasa un patrón re compilado) para hacer coincidencias de subcadenas o patrones en campos de texto:

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" hace que la coincidencia no distinga mayúsculas de minúsculas. Evita patrones con comodín inicial como .*texto en colecciones grandes — no pueden usar un índice y realizarán un escaneo completo de la colección.

Proyección — Devolver Solo Campos Específicos

Por defecto, find() devuelve todos los campos del documento, incluido _id. Usa un segundo argumento (la proyección) para incluir o excluir campos.

Incluir campos específicos

Pasa 1 para cada campo que quieras. Solo se devuelven esos campos (más _id):

# 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

Pasa 0 para cada campo que quieras ocultar. Se devuelven todos los demás campos:

# 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}
# ...

No puedes mezclar 1 y 0 en la misma proyección (excepto _id, que siempre puede establecerse a 0 junto con inclusiones).

Ordenar Resultados

Encadena .sort() en el cursor para ordenar los resultados. Usa pymongo.ASCENDING (1) o 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  65

Pasa una lista de tuplas (campo, dirección) para ordenar por múltiples 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   22

Consulta MongoDB Sort para profundizar en las opciones de ordenación.

Limitar y Paginar Resultados

limit()

limit(n) detiene el cursor después de devolver 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   77

skip() para paginación

Combina skip() y limit() para implementar una navegación sencilla 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  74

Para colecciones grandes, prefiere la paginación basada en rangos — filtra por el último _id visto o por una marca de tiempo — porque skip() igualmente escanea internamente los documentos omitidos.

Consulta MongoDB Limit para más detalles.

Contar Documentos

Usa count_documents() con el mismo diccionario de filtro para contar sin recuperar datos:

total = col.count_documents({})
london = col.count_documents({"city": "London"})
print(f"Total: {total}, In London: {london}")
# Total: 5, In London: 2

Evita el obsoleto cursor.count() — fue eliminado en PyMongo 4.

Errores Comunes

Los cursores de PyMongo se agotan tras la iteración. Una vez que recorres un cursor, queda vacío. Guarda los resultados en una lista si necesitas iterar más de una vez:

docs = list(col.find({"city": "London"}))
print(len(docs))   # 2
print(docs[0]["name"])  # Alice

_id es un ObjectId, no un string. Si almacenas un _id como string e intentas consultarlo después, la consulta no devolverá nada. Importa ObjectId desde bson para convertirlo:

from bson import ObjectId

doc = col.find_one({"_id": ObjectId("665000000000000000000001")})

Las consultas distinguen mayúsculas de minúsculas por defecto. {"city": "london"} no coincidirá con documentos almacenados como "London". Usa $regex con $options: "i" para coincidencias sin distinción de mayúsculas, o normaliza los valores al insertar.

Próximos Pasos

Was this page helpful?