Ограничение результатов в MongoDB
Узнайте, как использовать метод limit() в PyMongo для ограничения результатов, комбинировать его с skip() для пагинации и цеплять с sort() для упорядоченного вывода.
Метод limit() в PyMongo позволяет ограничить количество документов, возвращаемых запросом. На этой странице объясняется, что делает limit(), когда его использовать, как комбинировать его с skip() для пагинации и как цеплять с sort() для упорядоченных ограниченных результирующих наборов.
Предварительные требования
Вам понадобится установленный PyMongo и работающий экземпляр MongoDB. Установите драйвер командой:
pip install pymongoЗатем подключитесь к базе данных:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
col = db["customers"]Если вы только начинаете работать с подключением и вставкой документов, сначала ознакомьтесь с главами MongoDB — Начало работы и MongoDB — Вставка данных.
Что делает limit()
Вызов .limit(n) на курсоре сообщает MongoDB вернуть не более n документов. Без него find() возвращает все совпадающие документы, что может быть дорогостоящим на больших коллекциях.
# Returns ALL documents — can be slow on large collections
all_docs = col.find()
# Returns at most 5 documents
five_docs = col.find().limit(5)Передача 0 в limit() обрабатывается так же, как если бы он не был вызван вовсе: MongoDB вернёт все совпадающие документы.
# These two are equivalent — both return all documents
col.find().limit(0)
col.find()Базовый пример
Следующий скрипт вставляет десять образцов документов клиентов, а затем извлекает только первые три:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
col = db["customers"]
# Insert sample data (skip if your collection already has data)
col.drop()
names = ["Alice", "Bob", "Charlie", "Diana", "Eve",
"Frank", "Grace", "Hank", "Iris", "Jack"]
col.insert_many([{"name": n, "rank": i + 1} for i, n in enumerate(names)])
# Retrieve only the first 3 documents
results = col.find({}, {"_id": 0}).limit(3)
for doc in results:
print(doc)Ожидаемый вывод:
{'name': 'Alice', 'rank': 1}
{'name': 'Bob', 'rank': 2}
{'name': 'Charlie', 'rank': 3}Второй аргумент find() — это проекция: {"_id": 0} подавляет поле _id, чтобы вывод было легче читать.
Комбинирование limit() с sort()
limit() наиболее полезен в паре с sort(). Без сортировки MongoDB возвращает документы в естественном порядке (порядке вставки для свежей коллекции, но не гарантированном после обновлений или удалений). Предварительная сортировка гарантирует, что результаты «топ N» будут иметь смысл.
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
col = client["mydatabase"]["customers"]
# Top 3 customers by rank (ascending)
top3 = col.find({}, {"_id": 0}).sort("rank", pymongo.ASCENDING).limit(3)
print("Top 3 by rank:")
for doc in top3:
print(doc)
# Bottom 3 customers by rank (descending = highest rank number first)
bottom3 = col.find({}, {"_id": 0}).sort("rank", pymongo.DESCENDING).limit(3)
print("\nBottom 3 by rank:")
for doc in bottom3:
print(doc)Ожидаемый вывод:
Top 3 by rank:
{'name': 'Alice', 'rank': 1}
{'name': 'Bob', 'rank': 2}
{'name': 'Charlie', 'rank': 3}
Bottom 3 by rank:
{'name': 'Jack', 'rank': 10}
{'name': 'Iris', 'rank': 9}
{'name': 'Hank', 'rank': 8}Полное руководство по параметрам сортировки смотрите в главе MongoDB Sort.
Пагинация с помощью skip() и limit()
skip(n) указывает MongoDB пропустить первые n документов перед применением limit(). Вместе они реализуют постраничную пагинацию:
page_1 = skip(0).limit(page_size)
page_2 = skip(page_size).limit(page_size)
page_N = skip((N-1) * page_size).limit(page_size)Ниже представлен многократно используемый вспомогательный метод, который извлекает по одной странице за раз:
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
col = client["mydatabase"]["customers"]
def get_page(collection, page_number, page_size, sort_field="rank"):
"""Return one page of documents (1-indexed page numbers)."""
offset = (page_number - 1) * page_size
cursor = (
collection.find({}, {"_id": 0})
.sort(sort_field, pymongo.ASCENDING)
.skip(offset)
.limit(page_size)
)
return list(cursor)
# Fetch pages of 3 documents each
page1 = get_page(col, page_number=1, page_size=3)
page2 = get_page(col, page_number=2, page_size=3)
page3 = get_page(col, page_number=3, page_size=3)
print("Page 1:", page1)
print("Page 2:", page2)
print("Page 3:", page3)Ожидаемый вывод:
Page 1: [{'name': 'Alice', 'rank': 1}, {'name': 'Bob', 'rank': 2}, {'name': 'Charlie', 'rank': 3}]
Page 2: [{'name': 'Diana', 'rank': 4}, {'name': 'Eve', 'rank': 5}, {'name': 'Frank', 'rank': 6}]
Page 3: [{'name': 'Grace', 'rank': 7}, {'name': 'Hank', 'rank': 8}, {'name': 'Iris', 'rank': 9}]Предупреждение о производительности skip()
skip() работает путём сканирования и отбрасывания первых n документов перед возвратом результатов. На очень больших коллекциях (миллионы документов) большое значение skip() выполняется медленно, поскольку MongoDB всё равно должна прочитать все пропускаемые документы. Для высоконагруженной пагинации по большим наборам данных вместо этого используйте запрос по диапазону на индексированном поле:
# Instead of skip(1000).limit(10), remember the last _id from the previous page
# and filter: {"_id": {"$gt": last_seen_id}}
# This is O(log n) with an index rather than O(n)Комбинирование limit() с фильтрующим запросом
limit() работает с любым запросом find(), а не только с пустым find({}):
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
col = client["mydatabase"]["customers"]
# Find customers with rank greater than 5, return only the first 3
query = {"rank": {"$gt": 5}}
results = col.find(query, {"_id": 0}).sort("rank", pymongo.ASCENDING).limit(3)
for doc in results:
print(doc)Ожидаемый вывод:
{'name': 'Frank', 'rank': 6}
{'name': 'Grace', 'rank': 7}
{'name': 'Hank', 'rank': 8}Подробнее об операторах фильтрации ($gt, $lt, $in и др.) смотрите в главе MongoDB Query.
Порядок цепочки методов
PyMongo формирует запрос на стороне сервера, поэтому порядок, в котором вы цепляете sort(), skip() и limit() в Python, не влияет на результат — MongoDB всегда применяет их в последовательности: фильтр → сортировка → пропуск → ограничение. Следующие два выражения эквивалентны:
col.find().sort("rank", 1).skip(2).limit(3)
col.find().limit(3).skip(2).sort("rank", 1) # same resultЗапись в логическом порядке (sort → skip → limit) — это соглашение, которое делает код более читаемым.
Краткий справочник
| Метод | Назначение | Пример |
|---|---|---|
.limit(n) | Вернуть не более n документов | .find().limit(10) |
.skip(n) | Пропустить первые n документов | .find().skip(20) |
.sort(field, dir) | Сортировать перед ограничением | .find().sort("rank", 1).limit(5) |
.limit(0) | Без ограничения (возвращает все) | .find().limit(0) |
Связанные главы
- MongoDB Find — запрос документов с помощью
find()иfind_one() - MongoDB Query — фильтрация с операторами сравнения и логическими операторами
- MongoDB Sort — упорядочивание результатов с помощью
sort() - MongoDB Insert — добавление документов в коллекцию
- MongoDB Update — изменение существующих документов