Сортировка в MongoDB
Узнайте, как сортировать результаты запросов MongoDB в Python с помощью метода sort() PyMongo — по возрастанию, убыванию, нескольким полям.
В этой главе объясняется, как сортировать результаты запросов MongoDB в Python с помощью драйвера pymongo. Вы узнаете, как сортировать по одному полю в порядке возрастания или убывания, сортировать сразу по нескольким полям, комбинировать сортировку с фильтрацией и ограничением, а также понять, когда индекс ускоряет сортировку.
Предварительные требования
Вы должны уметь подключаться к MongoDB и выполнять запросы к документам. Если вы ещё не делали этого, сначала прочитайте MongoDB Find и MongoDB Query.
В примерах ниже предполагается наличие коллекции products в базе данных store. Вставить образцы документов, используемых на этой странице, можно следующим образом:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["store"]
col = db["products"]
# Insert sample data (skip if already inserted)
col.drop()
col.insert_many([
{"name": "Keyboard", "category": "Electronics", "price": 49.99, "stock": 120},
{"name": "Mouse", "category": "Electronics", "price": 29.99, "stock": 85},
{"name": "Desk", "category": "Furniture", "price": 249.99, "stock": 30},
{"name": "Chair", "category": "Furniture", "price": 189.99, "stock": 45},
{"name": "Monitor", "category": "Electronics", "price": 319.99, "stock": 60},
{"name": "Lamp", "category": "Furniture", "price": 39.99, "stock": 200},
])
print("Sample data inserted.")Метод sort()
Метод sort() вызывается на курсоре (объекте, возвращённом методом find()) и указывает MongoDB, в каком порядке возвращать документы. Его сигнатура:
cursor.sort(key_or_list, direction=None)key_or_list— имя поля (string) при сортировке по одному полю или список кортежей(field, direction)при сортировке по нескольким полям.direction—pymongo.ASCENDING(значение1) илиpymongo.DESCENDING(значение-1). Обязателен, когдаkey_or_listявляется простой строкой; опускается при использовании формы со списком.
Использование именованных констант (pymongo.ASCENDING / pymongo.DESCENDING) вместо числовых значений делает код более читаемым и помогает избежать ошибок на единицу.
Сортировка по возрастанию
Передайте pymongo.ASCENDING вторым аргументом для сортировки от наименьшего к наибольшему значению:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["store"]
col = db["products"]
results = col.find({}, {"_id": 0, "name": 1, "price": 1}).sort("price", pymongo.ASCENDING)
for doc in results:
print(doc)Ожидаемый вывод (начиная с самых дешёвых):
{'name': 'Mouse', 'price': 29.99}
{'name': 'Lamp', 'price': 39.99}
{'name': 'Keyboard', 'price': 49.99}
{'name': 'Chair', 'price': 189.99}
{'name': 'Desk', 'price': 249.99}
{'name': 'Monitor', 'price': 319.99}Проекция {"_id": 0, "name": 1, "price": 1} ограничивает возвращаемые поля значениями name и price, что делает вывод лаконичным. Проекции рассмотрены в MongoDB Find.
Сортировка по убыванию
Передайте pymongo.DESCENDING, чтобы изменить порядок на обратный (от наибольшего к наименьшему):
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["store"]
col = db["products"]
results = col.find({}, {"_id": 0, "name": 1, "price": 1}).sort("price", pymongo.DESCENDING)
for doc in results:
print(doc)Ожидаемый вывод (начиная с самых дорогих):
{'name': 'Monitor', 'price': 319.99}
{'name': 'Desk', 'price': 249.99}
{'name': 'Chair', 'price': 189.99}
{'name': 'Keyboard', 'price': 49.99}
{'name': 'Lamp', 'price': 39.99}
{'name': 'Mouse', 'price': 29.99}Сортировка по нескольким полям
Если нужно сортировать более чем по одному полю — например, сначала по категории, а затем по цене внутри каждой категории — передайте список кортежей (field, direction):
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["store"]
col = db["products"]
results = col.find({}, {"_id": 0, "name": 1, "category": 1, "price": 1}).sort([
("category", pymongo.ASCENDING),
("price", pymongo.ASCENDING),
])
for doc in results:
print(doc)Ожидаемый вывод (категории от А до Я, внутри каждой категории — от дешёвых к дорогим):
{'name': 'Mouse', 'category': 'Electronics', 'price': 29.99}
{'name': 'Keyboard', 'category': 'Electronics', 'price': 49.99}
{'name': 'Monitor', 'category': 'Electronics', 'price': 319.99}
{'name': 'Lamp', 'category': 'Furniture', 'price': 39.99}
{'name': 'Chair', 'category': 'Furniture', 'price': 189.99}
{'name': 'Desk', 'category': 'Furniture', 'price': 249.99}Поля сортировки применяются слева направо: MongoDB сначала сортирует все документы по category, а затем разрешает совпадения внутри одного значения категории по price.
Комбинирование sort() с фильтрацией
sort() работает с любым фильтром запроса. Фильтр выбирает подходящие документы, а sort() упорядочивает только их:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["store"]
col = db["products"]
# Find Electronics only, sorted cheapest first
query = {"category": "Electronics"}
fields = {"_id": 0, "name": 1, "price": 1}
results = col.find(query, fields).sort("price", pymongo.ASCENDING)
for doc in results:
print(doc)Ожидаемый вывод:
{'name': 'Mouse', 'price': 29.99}
{'name': 'Keyboard', 'price': 49.99}
{'name': 'Monitor', 'price': 319.99}Дополнительные варианты фильтрации, такие как запросы диапазонов ($gt, $lt) и сопоставление с шаблоном, см. в MongoDB Query.
Комбинирование sort() с limit()
Объедините в цепочку limit() после sort(), чтобы получить первые (или последние) N документов. Порядок цепочки не важен — MongoDB всегда применяет сортировку перед ограничением:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["store"]
col = db["products"]
# Top 3 most expensive products
results = col.find({}, {"_id": 0, "name": 1, "price": 1}) \
.sort("price", pymongo.DESCENDING) \
.limit(3)
for doc in results:
print(doc)Ожидаемый вывод:
{'name': 'Monitor', 'price': 319.99}
{'name': 'Desk', 'price': 249.99}
{'name': 'Chair', 'price': 189.99}Подробнее об управлении количеством возвращаемых документов читайте в MongoDB Limit.
Производительность: используйте индекс для больших коллекций
Для небольших коллекций MongoDB сортирует результаты в памяти. На большой коллекции сортировка в памяти может быть медленной, а если объём превысит 100 МБ — MongoDB вернёт ошибку. Создание индекса по полю сортировки позволяет MongoDB возвращать предварительно упорядоченные данные без сканирования всей коллекции:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["store"]
col = db["products"]
# Create a single-field index on price (ascending)
col.create_index([("price", pymongo.ASCENDING)])
# Queries that sort by price now use the index automatically
results = col.find({}, {"_id": 0, "name": 1, "price": 1}).sort("price", pymongo.ASCENDING)
for doc in results:
print(doc)Для сортировки по нескольким полям создайте составной индекс, поля и направления которого совпадают с вашей сортировкой:
col.create_index([
("category", pymongo.ASCENDING),
("price", pymongo.ASCENDING),
])Каждый индекс нужно создавать лишь один раз. Повторные вызовы create_index() с теми же ключами безопасны — PyMongo проверяет, существует ли индекс.
Безопасное хранение строки подключения
В приведённых выше примерах строка подключения жёстко задана в коде для простоты. В реальном приложении храните её в переменной окружения:
import os
import pymongo
client = pymongo.MongoClient(os.environ["MONGODB_URI"])Задайте переменную в командной оболочке (export MONGODB_URI="mongodb://localhost:27017/") или используйте файл .env с библиотекой, например python-dotenv.
Итоги
| Задача | Шаблон кода |
|---|---|
| Сортировка по возрастанию | .sort("field", pymongo.ASCENDING) |
| Сортировка по убыванию | .sort("field", pymongo.DESCENDING) |
| Сортировка по нескольким полям | .sort([("f1", pymongo.ASCENDING), ("f2", pymongo.DESCENDING)]) |
| Первые N результатов | .sort(...).limit(N) |
| Быстрая сортировка больших данных | Создайте индекс по полю сортировки |
Связанные главы этой серии:
- MongoDB Find — получение документов с помощью
find()иfind_one() - MongoDB Query — фильтрация с операторами запросов
- MongoDB Limit — управление количеством возвращаемых документов
- MongoDB Update — изменение документов в коллекции