Урок 84. MongoDB и Python. Модули

📁 Блок: Базы данных и модули ⏱️ Время изучения: ~90 мин 🎯 Сложность: Средняя
#close #find #sort #list #in #import #from

⚡ Кратко: типичные ошибки

  • Считать, что 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 ...

Правильно:

products.update_one({"name": "Notebook"}, {"$set": {"price": 24.99}})
4

Ловить общий Exception вместо pymongo.errors

Общий 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 всё равно рекомендуется.

Правильно:

my_project/
├── main.py
└── tools/
    ├── __init__.py
    └── text_utils.py