education-chat-be / mongodb_config.py
zuleleee's picture
Upload 4 files
78ebe75 verified
"""
MongoDB Configuration and Connection Manager
Replaces SQLite with MongoDB for the Adaptive Learning Platform
"""
import sys
import logging
import os
logger = logging.getLogger(__name__)
# Check for bson import conflict before importing pymongo
try:
import bson
# Check if this is the standalone bson package (which doesn't have SON)
if not hasattr(bson, 'SON') and not hasattr(bson, 'objectid'):
logger.error("""
⚠️ BSON Import Conflict Detected!
A standalone 'bson' package is installed that conflicts with pymongo.
This will cause import errors.
To fix this, run:
pip uninstall bson
pip install --upgrade pymongo
Or see: BSON_CONFLICT_FIX.md for detailed instructions.
""")
# Don't exit - let pymongo fail with a clearer error
except ImportError:
pass # bson not installed, which is fine
from pymongo import MongoClient, ASCENDING, DESCENDING
from pymongo.errors import ConnectionFailure, OperationFailure
try:
from bson.objectid import ObjectId
except ImportError:
# Fallback if standalone bson package conflicts
try:
from pymongo.bson.objectid import ObjectId
except ImportError:
# Last resort - try direct import
import pymongo
ObjectId = pymongo.bson.objectid.ObjectId
from datetime import datetime
from typing import Optional, Dict, Any, List
# MongoDB Configuration
MONGODB_CONNECTION_STRING = "mongodb+srv://raziullah0316_db_user:8GXp76aJwsg2i6Rn@learning.tlwwzix.mongodb.net/"
MONGODB_DATABASE_NAME = "learning"
class MongoDBManager:
"""MongoDB Connection and Operations Manager"""
def __init__(self):
self.client: Optional[MongoClient] = None
self.db = None
self._connected = False
def connect(self) -> bool:
"""Connect to MongoDB"""
try:
self.client = MongoClient(
MONGODB_CONNECTION_STRING,
serverSelectionTimeoutMS=5000,
connectTimeoutMS=10000,
retryWrites=True,
w='majority'
)
# Test connection
self.client.admin.command('ping')
self.db = self.client[MONGODB_DATABASE_NAME]
self._connected = True
logger.info(f"✅ Connected to MongoDB: {MONGODB_DATABASE_NAME}")
self._create_indexes()
return True
except ConnectionFailure as e:
logger.error(f"❌ Failed to connect to MongoDB: {e}")
self._connected = False
return False
except Exception as e:
logger.error(f"❌ Unexpected error connecting to MongoDB: {e}")
self._connected = False
return False
def _create_indexes(self):
"""Create indexes for better performance"""
try:
# Admins collection
self.db.admins.create_index([("username", ASCENDING)], unique=True)
# Students collection
self.db.students.create_index([("student_id", ASCENDING)], unique=True)
self.db.students.create_index([("email", ASCENDING)])
# Syllabi collection
self.db.syllabi.create_index([("title", ASCENDING)])
self.db.syllabi.create_index([("uploaded_at", DESCENDING)])
# Assessments collection
self.db.assessments.create_index([("student_id", ASCENDING)])
self.db.assessments.create_index([("syllabus_id", ASCENDING)])
self.db.assessments.create_index([("created_at", DESCENDING)])
# MCQ Questions collection
self.db.mcq_questions.create_index([("syllabus_id", ASCENDING)])
self.db.mcq_questions.create_index([("topic", ASCENDING)])
# Student Answers collection
self.db.student_answers.create_index([("student_id", ASCENDING), ("assessment_id", ASCENDING)])
# Learning Paths collection
self.db.learning_paths.create_index([("student_id", ASCENDING)])
self.db.learning_paths.create_index([("status", ASCENDING)])
# Chat Sessions collection
self.db.chat_sessions.create_index([("student_id", ASCENDING)])
self.db.chat_sessions.create_index([("created_at", DESCENDING)])
# Learning Progress collection
self.db.learning_progress.create_index([("student_id", ASCENDING)])
self.db.learning_progress.create_index([("learning_path_id", ASCENDING)])
# Microsoft Forms collection
self.db.microsoft_forms.create_index([("subject", ASCENDING)])
self.db.microsoft_forms.create_index([("grade", ASCENDING)])
self.db.microsoft_forms.create_index([("is_active", ASCENDING)])
self.db.microsoft_forms.create_index([("created_at", DESCENDING)])
# Microsoft Form Submissions collection
self.db.microsoft_form_submissions.create_index([("student_id", ASCENDING)])
self.db.microsoft_form_submissions.create_index([("form_id", ASCENDING)])
self.db.microsoft_form_submissions.create_index([("subject", ASCENDING)])
self.db.microsoft_form_submissions.create_index([("submitted_at", DESCENDING)])
logger.info("✅ MongoDB indexes created successfully")
except Exception as e:
logger.warning(f"⚠️ Failed to create some indexes: {e}")
def is_connected(self) -> bool:
"""Check if connected to MongoDB"""
return self._connected and self.client is not None
def close(self):
"""Close MongoDB connection"""
if self.client:
self.client.close()
self._connected = False
logger.info("MongoDB connection closed")
def serialize_doc(self, doc: Optional[Dict]) -> Optional[Dict]:
"""Convert MongoDB document to JSON-serializable format"""
if doc is None:
return None
doc = dict(doc) # Make a copy
if "_id" in doc:
doc["id"] = str(doc["_id"])
del doc["_id"]
for key, value in doc.items():
if isinstance(value, ObjectId):
doc[key] = str(value)
elif isinstance(value, datetime):
doc[key] = value.isoformat()
elif isinstance(value, dict):
doc[key] = self.serialize_doc(value)
elif isinstance(value, list):
doc[key] = [self.serialize_doc(item) if isinstance(item, dict) else item for item in value]
return doc
def get_object_id(self, id_str: str) -> ObjectId:
"""Convert string to ObjectId"""
try:
return ObjectId(id_str)
except:
return None
# Global MongoDB instance
mongodb = MongoDBManager()
# Helper functions for backward compatibility with SQLite code
def get_db():
"""Get MongoDB database instance (replaces SQLAlchemy session)"""
if not mongodb.is_connected():
mongodb.connect()
return mongodb.db
def serialize_document(doc: Dict) -> Dict:
"""Serialize MongoDB document"""
return mongodb.serialize_doc(doc)