Считать, что find() возвращает список — это курсор.
Перепутать фильтр и проекцию в find().
Обновлять документ без модификатора ($set, $inc).
Ловить общий Exception вместо исключений pymongo.errors.
Писать исполняемый код в модуле без if __name__ == "__main__".
🐛 Типичные ошибки
1
find() возвращает курсор, а не список
Метод find() возвращает объект-курсор, который можно перебрать только один раз. Если попытаться использовать его как список, можно получить неожиданный результат.
Неправильно:
docs = products.find()
print(len(docs)) # TypeError: объект Cursor не имеет длины
print(docs[0]) # TypeError: индексация недоступна
Правильно:
docs = list(products.find()) # если нужен список
print(len(docs))
# или перебрать курсор
for doc in products.find():
print(doc)
2
Перепутать фильтр и проекцию
В find(filter, projection) первый аргумент — условие выборки, второй — какие поля вернуть. Если перепутать их, запрос отработает некорректно.
Неправильно:
# Хотели найти товары дешевле 5, а получили проекцию как фильтр
for doc in products.find({"name": 1, "price": 1}):
print(doc) # вернёт документы, где name == 1 и price == 1
Правильно:
for doc in products.find({"price": {"$lt": 5}}, {"name": 1, "price": 1, "_id": 0}):
print(doc)
3
Обновить документ без модификатора
В MongoDB нельзя передать в update_one просто новый документ — нужен модификатор, например $set или $inc. Иначе произойдёт ошибка.
Неправильно:
products.update_one({"name": "Notebook"}, {"price": 24.99})
# WriteError: modifiers operate on fields but ...
Общий Exception скрывает тип ошибки и мешает понять, в подключении ли проблема или в запросе.
Неправильно:
try:
client.admin.command("ping")
except Exception as e:
print("Error:", e)
Правильно:
from pymongo import errors
try:
client.admin.command("ping")
except errors.ConnectionFailure:
print("Не удалось подключиться к MongoDB")
except errors.OperationFailure:
print("Ошибка авторизации или запроса")
5
Исполняемый код в модуле без if __name__ == "__main__"
Если в файле модуля написать код верхнего уровня, он выполнится при импорте. Это мешает повторному использованию модуля.
Неправильно:
# math_utils.py
print("Loading module...")
def average(numbers):
return sum(numbers) / len(numbers)
# Этот print выполнится и при импорте
print(average([1, 2, 3]))
Правильно:
# math_utils.py
print("Loading module...")
def average(numbers):
return sum(numbers) / len(numbers)
if __name__ == "__main__":
# Этот код выполнится только при прямом запуске файла
print(average([1, 2, 3]))
6
Забыть файл __init__.py в пакете
В Python папка без __init__.py (в старых версиях) не считается пакетом, и импорт из неё не сработает. В Python 3.3+ есть namespace packages, но явный __init__.py всё равно рекомендуется.