Сегодня познакомимся с интересным инструментом - NoSQL базой данных. Ранее мы мучали MySQL и подобные базы, которые требуют много внимания к SQL-запросам и структуре таблицы. Теперь мы познакомимся с идеальной базой данных для не структурированной информации. То есть мы избавимся от строгого синтаксиса и сможем легко дополнять записи новой информацией. В этом огромный плюс NoSQL-базы для написания различных ботов, которые в дальнейшем будут масштабироваться.
Что такое MongoDB и NoSQL простыми словами
Перед созданием кода разберёмся с терминами. MongoDB - популярная NoSQL база данных, которая хранит данные не в таблицах, а в документах. Формат документов похож на JSON.
Чем NoSQL база данных отличается от привычных SQL (MySQL, PostgreSQL):
- В SQL данные лежат в таблицах со строгими столбцами. Добавить новое поле - надо менять схему всей таблицы.
- В NoSQL базе данных MongoDB данные - это документы, и у каждого может быть свой набор полей. Захотели добавить поле одному пользователю - просто добавили, остальных не трогаем.
Основные понятия MongoDB:
- База данных (database) - контейнер для коллекций, как и в SQL.
- Коллекция (collection) - аналог таблицы в SQL, но без жёсткой структуры.
- Документ (document) - одна запись, похожая на словарь Python или JSON-объект.
- Поле (field) - пара ключ-значение внутри документа.
Главный плюс MongoDB - гибкость. Не нужно заранее проектировать жёсткую схему. Это удобно для проектов где структура данных меняется: боты, логи, пользовательские профили, каталоги товаров с разными характеристиками.
MongoDB или SQL: когда что выбирать
Частый вопрос новичков - брать MongoDB или классический SQL. Однозначного ответа нет, зависит от задачи.
| Критерий | MongoDB (NoSQL) | SQL (PostgreSQL, MySQL) |
|---|---|---|
| Структура данных | Гибкая, документы | Жёсткие таблицы и схемы |
| Связи между данными | Слабые, вложенность | Сильные, JOIN-ы |
| Масштабирование | Горизонтальное (шардинг) | Вертикальное |
| Транзакции | Есть, но проще | ACID из коробки |
| Когда брать | Логи, профили, каталоги, боты | Финансы, заказы, строгие связи |
Когда MongoDB - хороший выбор:
- Структура данных заранее неизвестна или часто меняется.
- Нужно быстро прототипировать без проектирования схемы.
- Данные естественно ложатся в документы (JSON из API, профили, события).
- Боты и приложения которые планируется масштабировать.
Когда лучше остаться на SQL:
- Данные сильно связаны (заказы, платежи, пользователи с ролями).
- Нужны сложные JOIN-ы и строгая целостность.
- Важны полноценные ACID-транзакции.
Многие проекты используют обе базы: SQL для строгих данных, MongoDB для гибких. Это нормальная практика.
Установка MongoDB и подготовка окружения
Сначала установим саму MongoBD: переходим на официальный сайт Mongo по ссылке и скачиваем сервер версии 6.0.3 под вашу операционную систему.

Для корректной установки следуйте примерам на скриншотах:


Важно тут выбрать пункт “Complete”. Этот пункт поставит все стандартные настройки и модули, что для начала нам подойдет. Потом, если будете изучать эту БД, сможете настраивать под себя:


В этом пункте важно поставить галочку на “Install MongoDB Compass” - на компьютер установится графический интерфейс для взаимодействия с СУБД.

После установки нам открывается программа MongoDB Compass, где уже вставлены данные для подключения к установленному серверу. Нажимаем кнопку "connect", и мы в нем:

Ниже пример как можно создать базу данных и коллекцию. Коллекции – это аналог таблиц в SQL-базах. В них мы храним информацию, которая нам нужна.

Подключение к MongoDB на Python через pymongo
Для Windows:
pip install pymongo fakerДля MacOS:
python pip install pymongo fakerДля знакомства с СУБД MongoDB нам хватит сделать несколько методов, таких как: добавление пользователя, получить всю коллекцию, изменить какое-то значение, поиск, по заданным критериям и на этом все. Если вам будет интересна эта СУБД, вы сможете самостоятельно ознакомиться с другими её возможностями.
Анонсы всех видео, статей и полезностей - в нашем Telegram🔥
Присоединяйтесь, обсуждайте и автоматизируйте!
У нас будет два файла - pymongoAPI.py и main.py (призываю вас всегда разделять проект на логические модули – это правильный тон в мире программистов Python). Первый файл будет отвечать за взаимодействие с БД, а во втором мы будем пытаться добавлять новые значения и что-то менять.
Импорты:
from pymongo import MongoClientДля всего взаимодействия с MongoDB потребуется только сам клиент, который и импортируем.
Класс взаимодействия с MongoDB:
class MongoDB(object):
def __init__(self, host: str = 'localhost',
port: int = 27017,
db_name: str = None,
collection: str = None):
self._client = MongoClient(f'mongodb://{host}:{port}')
self._collection = self._client[db_name][collection]
def create_user(self, user: dict):
try:
if self._collection.find_one({"username": user.get('username')}) == None:
self._collection.insert_one(user)
print(f"Added New user: {user.get('username')}")
else:
print(f"User: {user.get('username')} in collection")
except Exception as ex:
print("[create_user] Some problem...")
print(ex)
def get_all_users(self):
try:
data = self._collection.find()
print("Get all users")
return data
except Exception as ex:
print("[get_all] Some problem...")
print(ex)
def find_by_username(self, username: str):
try:
data = self._collection.find_one({"username": username})
print("Get user by username")
return data
except Exception as ex:
print("[find_by_username] Some problem...")
print(ex)
def change_user(self, username: str, key: str, value: str):
try:
if self._collection.find_one({"username": user.get('username')}) is not None:
self._collection.update_one({"username": username}, {"$set": {key: value}})
else:
print(f'User: {username} not find')
except Exception as ex:
print("[change_user] Some problem...")
print(ex)Разберёмся что за чем идет.
__init__ — это конструктор, он принимает в себя ip адрес сервера, порт, название базы данных и название коллекции. Он создает подключение к серверу и записывает в отдельную внутреннюю переменную. Дальше отдельно вытягивает в переменную нашу базу данных. Часто спрашивают зачем ставить нижней прочерк перед полем – это нужно, чтобы показать другим разработчикам, который показывает, что его трогать не надо (так принято показывать в Python приватные переменные).
Create_user – «кушает» словарь, это связанно с тем, что мы будем сразу передавать нового пользователя. Можно формировать его и внутри метода, но так проще. Сразу скажу, что все запросы к базам данных следует оборачивать в try… except, потому что в случае ошибки у нас не будет «падать» программа. В реальной жизни если из-за этой ошибки пользователи не смогу воспользоваться функциями, у вас могут быть проблемы.
Теперь переходим к сути. Обращаемся к методу find_one для проверки, существует ли пользователь в коллекции. Внутрь мы передаем словарь ключ (искомое поле) и значение. Если нам в ответ вернется None, то значит такого значения не существует, ну и если словарь, то значит пользователь существует (сразу отмечу, что username у нас будут индивидуальным значением, то есть не будет повторяться).
Дальше обращаемся к insert_one и передаем словарь пользователя. Чтобы видеть ошибки, мы делаем выводы в консоль о выполненном действии и в случае ошибки показываем модуль с ошибкой.
Get_all_users – с помощью этого метода будем выводить все записи в коллекции. Обращаемся к объекту коллекции и применяем метод find, без каких-либо значений. В ответ мы получаем массив значений и возвращаем его из метода.
Find_by_username – теперь будем искать по уникальному значению в виде username. Принимаем искомого пользователя и обращаемся к методу коллекции find_one. Он будет выводить первое совпадение и возвращать его словарем, если пользователя не существует, то вернется None.
Change_user – последний метод на сегодня, он будет менять значение. Принимает в себя username, key (изменяемое значение) и value (новое значение). В начале идет проверка на наложение пользователя в коллекции, потом используется update_one.
Что же это такое, метод, предоставляемый объектом коллекции для обновления записи? Первым значением идет словарь для поиска по значение, потом второй с служебным оператором $set с вложенным вторым словарем, внутри которого находится ключ и его новое значение (подробнее об служебных операторах по ссылке).
Работа с базой данных MongoDB: запись и чтение
Теперь идем проверять наш класс. Будем рассматривать код по строчкам, чтобы можно было посмотреть все по очереди и отслеживать, что меняется в БД. Импортируем наш MongoDB из файла mongoAPI. Так же библиотеку для создания несуществующих пользователей.
from mongoAPI import MongoDB
import fakerДальше создаем объект dbase на основе нашего класса, передаем в него название БД и коллекции с которой будем работать:
dbase = MongoDB(db_name='article', collection='user')Так же не стоит забывать про объект для создание «фейковых» пользователей:
faker_obj = faker.Faker()Создаем наш фейковый профиль и посмотрим вывод в консоль:
user_profile = faker_obj.simple_profile()
user_profile['birthdate'] = user_profile['birthdate'].strftime('%d/%m/%Y')
print(user_profile)Словарь состоит из логина, имени, пола, адреса, почты и даты рождения:
{'username': 'dparker', 'name': 'Megan Morris', 'sex': 'F', 'address': '15074 Conner Lane\nDavidshire, ME 67230', 'mail': 'leslie72@gmail.com', 'birthdate': '24/04/2017'}
Пробуем добавить его в коллекцию:
dbase.create_user(user_profile)Выводы в консоль:
{'username': 'ronald44', 'name': 'Carrie Armstrong', 'sex': 'F', 'address': '0829 Cook Key Apt. 678\nKatherinestad, CA 73382', 'mail': 'tammy73@hotmail.com', 'birthdate': '24/08/1998'}
Added New user: ronald44
Как выглядит все в коллекции:

Тут может возникнуть вопрос, что за значение _id? Это уникальный ID, который автоматически создает MongoDB. Можно провести аналогию с Primary Key в MySQL.
Давайте добавим пару случайных пользователей с помощью библиотеки faker и цикла for. Выглядит все так:
for _ in range(3):
user_profile = faker_obj.simple_profile()
user_profile['birthdate'] = user_profile['birthdate'].strftime('%d/%m/%Y')
dbase.create_user(user_profile)Добавили пользователей: xwilliams, kylewilliams и obrowning. Так это выглядит в коллекции:

Чтобы посмотреть полную сводку из коллекции надо будет воспользоваться циклом for. Это связано с тем, что в ответ нам идет объект Cursor:
result = dbase.get_all_users()
for i in result:
print(i)Вывод в консоль:
Get all users
{'_id': ObjectId('63790f4edc6a4ce30ed44398'), 'username': 'ronald44', 'name': 'Carrie Armstrong', 'sex': 'F', 'address': '0829 Cook Key Apt. 678\nKatherinestad, CA 73382', 'mail': 'tammy73@hotmail.com', 'birthdate': '24/08/1998'}
{'_id': ObjectId('637910f07d126aae084a4310'), 'username': 'xwilliams', 'name': 'Erin Simmons', 'sex': 'F', 'address': 'PSC 0729, Box 2069\nAPO AP 14417', 'mail': 'suzanne49@hotmail.com', 'birthdate': '05/04/1918'}
{'_id': ObjectId('637910f07d126aae084a4311'), 'username': 'kylewilliams', 'name': 'Jeffrey Miller', 'sex': 'M', 'address': '977 Santos Turnpike Apt. 039\nNew Cynthia, FM 81301', 'mail': 'christopher50@gmail.com', 'birthdate': '16/06/2016'}
{'_id': ObjectId('637910f07d126aae084a4312'), 'username': 'obrowning', 'name': 'Amy Thompson', 'sex': 'F', 'address': '041 Leah Locks Suite 280\nReedport, MI 56259', 'mail': 'vargassarah@hotmail.com', 'birthdate': '25/08/1915'}
Поиск человека по логину:
print(dbase.find_by_username('username'))Вывод в консоль:
Get user by username
{'_id': ObjectId('63790f4edc6a4ce30ed44398'), 'username': 'ronald44', 'name': 'Carrie Armstrong', 'sex': 'F', 'address': '0829 Cook Key Apt. 678\nKatherinestad, CA 73382', 'mail': 'tammy73@hotmail.com', 'birthdate': '24/08/1998'}
Теперь изменим пользователю имя на "тест":
dbase.change_user('ronald44', 'name', 'test')После запуска мы увидим в коллекции следующее:

CRUD-операции в MongoDB: полный набор
CRUD - четыре базовые операции с данными: Create (создать), Read (читать), Update (обновить), Delete (удалить). В нашем классе уже есть часть, разберём весь набор для MongoDB через pymongo.
Create - вставка документов:
# Один документ
collection.insert_one({"name": "Иван", "age": 30})
# Несколько сразу
collection.insert_many([
{"name": "Пётр", "age": 25},
{"name": "Мария", "age": 28},
])
Read - поиск документов:
# Найти один
user = collection.find_one({"name": "Иван"})
# Найти все подходящие
adults = collection.find({"age": {"$gte": 18}})
for u in adults:
print(u)
# С условиями: age больше 25 И name начинается на "П"
collection.find({"age": {"$gt": 25}, "name": {"$regex": "^П"}})
Update - обновление:
# Обновить одно поле
collection.update_one({"name": "Иван"}, {"$set": {"age": 31}})
# Обновить несколько документов
collection.update_many({"age": {"$lt": 18}}, {"$set": {"status": "несовершеннолетний"}})
Delete - удаление:
collection.delete_one({"name": "Иван"})
collection.delete_many({"status": "неактивный"})
Операторы запросов MongoDB которые пригодятся постоянно: $gt (больше), $gte (больше или равно), $lt (меньше), $in (входит в список), $regex (по регулярке), $set (установить значение), $exists (поле существует).
Индексы в MongoDB: ускоряем запросы
Когда документов в базе данных MongoDB становится много (десятки тысяч и больше), поиск без индексов начинает тормозить. MongoDB вынужден перебирать все документы подряд (collection scan).
Индекс - это структура которая позволяет находить нужные документы быстро, не перебирая всё.
Создаём индекс по полю:
collection.create_index("username")
# Уникальный индекс - запрещает дубли
collection.create_index("email", unique=True)
# Составной индекс по нескольким полям
collection.create_index([("age", 1), ("name", 1)])
Цифры 1 и -1 задают порядок сортировки в индексе (по возрастанию или убыванию).
Как понять что запрос тормозит и нужен индекс - метод explain():
collection.find({"username": "ronald44"}).explain()
В выводе смотрим на COLLSCAN (плохо, перебор всей коллекции) против IXSCAN (хорошо, использован индекс).
Правило простое: если по полю часто ищете - сделайте индекс. Но не плодите их без меры, каждый индекс занимает место и замедляет запись.
Агрегации в MongoDB: аналитика по данным
Когда нужно не просто достать документы, а посчитать что-то (среднее, суммы, группировки) - используется aggregation pipeline. Это конвейер этапов, через которые проходят данные.
Пример: посчитать сколько пользователей в каждом городе:
pipeline = [
{"$group": {"_id": "$city", "count": {"$sum": 1}}},
{"$sort": {"count": -1}},
]
result = collection.aggregate(pipeline)
for row in result:
print(row)
Основные этапы pipeline:
$match- фильтрация (как find, но в конвейере).$group- группировка с подсчётом.$sort- сортировка результата.$project- выбрать какие поля оставить.$limit- ограничить количество.
Более сложный пример - средний возраст по городам, только где больше 5 человек:
pipeline = [
{"$group": {"_id": "$city", "avg_age": {"$avg": "$age"}, "n": {"$sum": 1}}},
{"$match": {"n": {"$gt": 5}}},
{"$sort": {"avg_age": -1}},
]
Агрегации - мощный инструмент MongoDB, заменяющий многие SQL-запросы с GROUP BY. Для аналитики по данным в NoSQL базе это основной способ.
MongoDB Atlas: база данных в облаке
Поднимать MongoDB на своём сервере не обязательно - есть официальное облако MongoDB Atlas. Удобно когда не хочется возиться с установкой и администрированием.
Что даёт Atlas:
- Бесплатный тариф (M0) - до 512 МБ, хватает для пет-проектов и обучения.
- Автоматические бэкапы и репликация.
- Не нужно настраивать сервер - база поднимается за пару минут через веб-интерфейс.
- Подключение из кода тем же pymongo, меняется только строка подключения.
Подключение к Atlas из Python почти не отличается от локального - просто другой URI:
from pymongo import MongoClient
client = MongoClient(
"mongodb+srv://user:password@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority"
)
db = client["article"]
collection = db["user"]
Строку подключения берёте в панели Atlas (кнопка Connect). Дальше весь код работы с базой данных MongoDB - точно такой же как для локальной. Это и есть плюс: разработали локально, задеплоили в облако без переписывания.
FAQ: MongoDB и Python
Чем MongoDB отличается от SQL?
MongoDB - NoSQL база данных, хранит данные в гибких документах (как JSON), без жёсткой схемы. SQL хранит в таблицах со строгими столбцами. MongoDB удобнее когда структура данных меняется, SQL - когда нужны строгие связи и транзакции.
Какая библиотека нужна для работы с MongoDB на Python?
pymongo - официальный драйвер MongoDB для Python. Ставится через pip install pymongo. Через него создаётся подключение MongoClient и выполняются все операции с базой.
Можно ли использовать MongoDB бесплатно?
Да. MongoDB Community Edition бесплатна для self-hosted. Облако MongoDB Atlas имеет бесплатный тариф M0 (до 512 МБ) - хватает для обучения и небольших проектов.
Что такое коллекция в MongoDB?
Коллекция - аналог таблицы в SQL. В ней хранятся документы (записи). Отличие в том что у документов в одной коллекции могут быть разные поля - жёсткой структуры нет.
Когда выбирать MongoDB вместо PostgreSQL?
Когда структура данных гибкая или заранее неизвестна, нужно быстро прототипировать, данные ложатся в документы (профили, логи, каталоги). Для строгих связанных данных (финансы, заказы) лучше SQL.
Нужны ли индексы в MongoDB?
Да, как только данных становится много. Без индексов поиск перебирает всю коллекцию и тормозит. Индекс создаётся через collection.create_index("поле") и резко ускоряет запросы по этому полю.
Заключение
Сегодня мы тестировали СУБД MongoDB - сделали тестовое добавление коллекции и попробовали вносить в базу изменения.
Как вы видите, Mongo очень удобна и гибка, что позволяет легко масштабировать из маленького проекта в большой. Советую вам изучить её более подробно.
Полезные ссылки
Документации библиотеки pymongo: https://pymongo.readthedocs.io/en/stable/
Подробный курс на ютубе: https://www.youtube.com/playlist?list=PL6plRXMq5RABbVCM0dn23PTKO13WcXnbf