Your Acadly platform has been upgraded with MongoDB GridFS video streaming while keeping MySQL for authentication, user data, and progress tracking.
- ✅ Added
mongoosev8.0.0 - MongoDB ODM - ✅ Added
mongoose-gridfsv2.0.0 - GridFS support for large files - ✅ Added
multerv1.4.5 - File upload handling
Install with:
cd Backend
npm install- Connects to MongoDB via
MONGO_URIenvironment variable - Provides
getGridFSBucket()for file streaming - Handles connection pooling and graceful failures
- VideoMetadata: Stores video info, duration, fileSize, XP rewards, view counts
- VideoFeedback: Optional user ratings/reviews for videos
- Text indexes on title + description for full-text search
- ✅ Initializes MongoDB connection at startup
- ✅ Falls back gracefully if MongoDB unavailable
- ✅ Keeps existing MySQL connection intact
Removed unused MySQL category/topic/subcategory endpoints Added streaming endpoints:
| Endpoint | Method | Purpose |
|---|---|---|
GET /api/videos/ |
GET | List all published videos (MongoDB) |
GET /api/videos/:id/metadata |
GET | Get video metadata (MongoDB) |
GET /api/videos/:id/stream |
GET | Stream video file (GridFS) |
POST /api/videos/upload |
POST | Upload new video to GridFS (Admin) |
PUT /api/videos/:id/metadata |
PUT | Update video metadata (Admin) |
DELETE /api/videos/:id |
DELETE | Delete video + file (Admin) |
GET /api/videos/search/:query |
GET | Full-text search (MongoDB) |
POST /api/videos/:id/progress |
POST | Track watch progress (MySQL) |
GET /api/videos/:id/user-progress |
GET | Get user's progress (MySQL) |
- ✅ Updated video endpoint:
/api/videos/:id/stream - ✅ Changed demo badge to "Live from MongoDB"
- ✅ Updated progress tracking to use MongoDB video IDs
- ✅ Supports HTTP range requests for seeking
- ✅ Added
MONGO_URIsetting - ✅ Template for local and MongoDB Atlas connections
cd Backend
npm installCopy .env.example to .env:
cp .env.example .envUpdate .env with your configuration:
# MySQL (existing setup)
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_NAME=acadly_db
# MongoDB (NEW)
MONGO_URI=mongodb://localhost:27017/acadly_videosMongoDB Options:
- Local Development:
mongodb://localhost:27017/acadly_videos - MongoDB Atlas (Cloud):
mongodb+srv://username:password@cluster.mongodb.net/acadly_videos
# Windows with MongoDB installed
mongod
# Or using Docker
docker run -d -p 27017:27017 --name mongo mongo:latestcd Backend
npm start
# Server runs at http://localhost:3000You'll see:
✅ MySQL pool initialized
✅ MongoDB connected for video streaming
✅ Video routes mounted at /api/videos
✅ Server running at http://localhost:3000
1. User opens /videoplayer
↓
2. Clicks video in playlist (e.g., MongoDB ID: 507f1f77bcf86cd799439011)
↓
3. Browser: fetch('/api/videos/507f1f77bcf86cd799439011/stream')
↓
4. Backend route:
a) Validate ObjectId format
b) Look up VideoMetadata in MongoDB
c) Check if published & active
d) Open GridFS download stream
e) Send video bytes with proper MIME type & range support
↓
5. HTML5 <video> element receives stream
↓
6. User watches → timeupdate events → localStorage saves progress
↓
7. Video completes or quiz submitted:
POST /api/videos/:id/progress
└─→ MySQL records completion + awards XP
curl -X POST http://localhost:3000/api/videos/upload \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-F "videoFile=@myvideo.mp4" \
-F "title=Machine Learning Basics" \
-F "category=AI" \
-F "duration=1200" \
-F "description=An intro to ML concepts"Response:
{
"message": "Video uploaded successfully",
"video_id": "507f1f77bcf86cd799439011",
"file_id": "507f1f77bcf86cd799439001"
}# Simple stream
curl http://localhost:3000/api/videos/507f1f77bcf86cd799439011/stream \
-o video.mp4
# With range request (for seeking)
curl -H "Range: bytes=1000-2000" \
http://localhost:3000/api/videos/507f1f77bcf86cd799439011/streamcurl -X POST http://localhost:3000/api/videos/507f1f77bcf86cd799439011/progress \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"watch_seconds": 600,
"completed": 1,
"quiz_score": 100
}'Response:
{ "message": "Progress tracked" }The refactored /api/videos/:id/progress endpoint requires JWT token:
// On frontend
const token = localStorage.getItem("auth_token");
fetch(`/api/videos/${videoId}/progress`, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ completed: 1, watch_seconds: 600 })
});{
_id: ObjectId,
file_id: ObjectId, // GridFS file reference
title: String,
description: String,
category: String, // e.g., "Machine Learning"
subcategory: String,
duration: Number, // seconds
format: String, // "mp4", "webm"
mimeType: String, // "video/mp4"
fileSize: Number, // bytes
thumbnail: String, // URL or base64
xpReward: Number, // Default: 25
isPublished: Boolean,
isActive: Boolean,
views: Number,
rating: Number, // 0-5
uploadedBy: Number, // MySQL user_id
uploadedAt: Date,
tags: [String]
}user_id, video_id, watch_seconds, completed, quiz_score, xp_awarded, last_watched-
Video IDs Changed: Old numeric IDs → MongoDB ObjectIds
- Update frontend references to use correct MongoDB IDs
- Existing MySQL progress tracking still works (video_id is just stored as string)
-
GridFS Limits:
- Max file size: 5GB (configurable in
routes/videos.js) - Supported formats: MP4, WebM, MOV
- Max file size: 5GB (configurable in
-
Range Requests: Fully supported for seeking in videos
- Browser can seek without downloading entire file first
-
Backward Compatibility:
- MySQL progress tracking unchanged
- Auth routes unchanged
- Dashboard API unchanged
-
Performance:
- Index on
isPublished + isActivefor fast queries - Text indexes on
title + descriptionfor full-text search - View count incremented on each stream request
- Index on
# In Backend folder
node -e "
const { connectMongoDB } = require('./DataBase/db_config_mongo.js');
connectMongoDB().then(() => console.log('✅ Connected!')).catch(e => console.error('❌', e.message));
"# Upload test video
curl -X POST http://localhost:3000/api/videos/upload \
-H "Authorization: Bearer test_token" \
-F "videoFile=@test.mp4" \
-F "title=Test Video" \
-F "category=Testing" \
-F "duration=60"
# Then stream it using the returned video_id
curl http://localhost:3000/api/videos/{returned_video_id}/stream -o downloaded.mp41. Start server: npm start
2. Open http://localhost:3000/videoplayer
3. Click a video in the playlist
4. Should stream from MongoDBDataBase/db_config_mongo.js- MongoDB connection poolDataBase/schema-mongo.js- Mongoose schemas with GridFS.env.example- Updated with MONGO_URI
Backend/server.js- Added MongoDB initBackend/package.json- Added mongoose, multer, mongoose-gridfsBackend/routes/videos.js- Streamlined for GridFS (old MySQL categories removed)Frontend/videoplayer.html- Update video source endpoints
- MySQL connection (
db_config.js) - Auth routes
- Progress tracking (MySQL backend)
- User management routes
- Dashboard routes
-
Update Video References:
- Get real MongoDB video IDs from your uploads
- Update
Frontend/videoplayer.htmlplaylist with actual IDs
-
Bulk Migrate Old Videos (Optional):
- Create migration script to upload old videos to MongoDB
- Keep MySQL metadata in sync
-
Add Admin Upload UI:
- Create form page for teachers to upload videos
- Connect to
/api/videos/uploadendpoint
-
Monitor Storage:
- MongoDB GridFS stores all video files
- Monitor disk space and set retention policies
-
Scale in Production:
- Use MongoDB Atlas for managed database
- Enable encryption at rest
- Set up automated backups
MongoDB Connection Fails:
- Ensure MongoDB is running:
mongodor check Docker - Check
.envMONGO_URI is correct - Test:
mongo mongodb://localhost:27017/acadly_videos
Video Won't Stream:
- Check file_id in VideoMetadata matches GridFS
- Verify
isPublished: truein metadata - Check browser console for 404/403 errors
Upload Times Out:
- Increase multer
fileSizelimit inroutes/videos.js - Check network speed and MongoDB connection
- Monitor MongoDB logs
Progress Not Saving:
- Verify auth_token is in localStorage
- Check JWT token is valid
- Ensure MySQL connection is working
Your Acadly platform now has:
- ✅ MongoDB GridFS for efficient video storage & streaming
- ✅ Refactored API with clean streaming endpoints
- ✅ HTTP Range Support for seek-without-download
- ✅ Full-Text Search on videos
- ✅ Backward Compatible progress tracking via MySQL
- ✅ Production Ready error handling and validation
Happy teaching! 🎓📹