
Я сделал небольшой эксперимент и показал, как можно хранить данные пользователей телеграм-бота без Postgres или MySQL. В проекте «Помощник программиста» для этого достаточно одного users.json и пары методов Python. Такой подход идеально подходит для MVP и небольших ботов.
Почему именно JSON?
- Быстрый старт — не нужно поднимать базы и настраивать ORM
- Данные всегда под рукой — файл лежит рядом с кодом
- Подходит для одного инстанса (например, на Render или Railway)
- Хватает для учёта пользователей, статистики и простых настроек
Каркас хранилища
class UserDatabase: def __init__(self, db_file="users.json"): self.db_file = db_file self.users_data = self._load() def get_user(self, user_id: int): key = str(user_id) if key not in self.users_data: self.users_data[key] = { "user_id": user_id, "created_at": datetime.now().isoformat(), "total_questions": 0, "favorite_topics": [] } self._save() return self.users_data[key] - Метод
get_userсоздаёт запись, если её нет - JSON сохраняется в человеко-читаемом виде (
indent=2,ensure_ascii=False) - Ошибки загрузки/сохранения логируются, но не ломают бота
Что умеет база
increment_questions(user_id)— увеличивает счётчик вопросовadd_topic_interest(user_id, topic)— хранит интересы пользователя (до 10 последних)get_active_users(days=7)— считает активных за неделю- Методы
update_userиget_userработают как мини-ORM
Интеграция в команды
stats = user_db.get_user(user_id) text = ( f" Ваша статистика:\n\n" f"• Всего вопросов: {stats['total_questions']}\n" f"• Последняя активность: {stats['last_active']}\n" ) await update.message.reply_text(text) /start— создаёт запись о пользователе/stats— показывает статистику из JSON/admin— доступен экспорт CSV с пользователями
Экспорт базы
async def _send_admin_export_csv(query): fieldnames = ["user_id", "username", "total_questions", "created_at", "last_active"] stream = StringIO() writer = csv.DictWriter(stream, fieldnames=fieldnames) writer.writeheader() for record in user_db.users_data.values(): writer.writerow(record) buffer = BytesIO(stream.getvalue().encode("utf-8")) buffer.seek(0) filename = f"users_export_{datetime.utcnow():%Y%m%d_%H%M%S}.csv" await query.message.reply_document( document=InputFile(buffer, filename=filename), caption="Экспорт пользователей (UTF-8)" ) - Файл собирается в памяти через
csv.DictWriter - Сохраняется в UTF-8, чтобы открывался в Excel/Google Sheets
- Доступен только администратору (проверка username)
Когда JSON перестанет хватать
- Если пользователей уже тысячи и нужно горизонтальное масштабирование
- Если появляются требования к аудиту и отчётам
- Если нужна отказоустойчивость
Тогда миграция на SQLite или Postgres делается безболезненно — интерфейс UserDatabase можно сохранить, заменив только реализацию.
Выводы
- JSON идеально подходит для MVP и учебных проектов
- Удобен в отладке, прост в поддержке
- Даёт профили пользователей, статистику и экспорт без сложной инфраструктуры
Этот подход я использую в своём проекте «Помощник Программиста». Если нужен бот с памятью, админкой и статистикой — пишите:
- vadzim.by
- Telegram: @vadzim_belarus
- Попробовать бота: @vadzim_by_programmer_bot