MongoDB Configuration and Setup - pacificnm/wiki-ai GitHub Wiki
This document provides comprehensive information about MongoDB configuration, connection, and usage in the wiki-ai project.
The wiki-ai project uses MongoDB Atlas (cloud-hosted MongoDB) with Mongoose as the ODM (Object Document Mapper). The database configuration includes connection management, retry logic, health checking, and automatic initialization.
# MongoDB Atlas Configuration
MONGO_URI=mongodb+srv://username:[email protected]/?retryWrites=true&w=majority&appName=ClusterName
MONGO_DB_NAME=wiki-ai
# Optional Configuration
LOG_LEVEL=info
NODE_ENV=development
mongodb+srv://<username>:<password>@<cluster-url>/?retryWrites=true&w=majority&appName=<app-name>
Components:
-
<username>
: MongoDB Atlas database user -
<password>
: Database user password -
<cluster-url>
: Your cluster's connection URL -
retryWrites=true
: Automatically retry write operations -
w=majority
: Write concern for replica sets -
appName
: Application identifier for monitoring
The database is configured with optimized settings for MongoDB Atlas:
const connectionOptions = {
maxPoolSize: 10, // Maximum 10 concurrent connections
serverSelectionTimeoutMS: 10000, // 10 seconds to select server
socketTimeoutMS: 45000, // 45 seconds socket timeout
connectTimeoutMS: 10000, // 10 seconds connection timeout
maxIdleTimeMS: 30000, // 30 seconds idle timeout
retryWrites: true, // Retry failed writes
w: 'majority' // Write concern
};
- Automatic Retry Logic: Exponential backoff with up to 5 retry attempts
- Connection Pooling: Efficient connection reuse
- Health Monitoring: Continuous connection health checks
- Graceful Shutdown: Proper cleanup on application termination
- Error Handling: Comprehensive error logging and recovery
The wiki-ai database uses the following collections:
Collection | Purpose | Key Features |
---|---|---|
users |
User accounts and profiles | Firebase UID integration, role-based access |
documents |
Wiki documents and metadata | Versioning, categorization, tagging |
versions |
Document version history | Markdown content, change tracking |
categories |
Document organization | Hierarchical structure, slug-based URLs |
comments |
Document comments | Version-specific commenting |
attachments |
File attachments | Document and version linking |
logs |
Application logging | Structured error and activity logs |
aisuggestions |
AI-generated content | Tags, summaries, and suggestions |
accesscontrol |
Document sharing | User permissions and access levels |
favorites |
User bookmarks | Quick access to preferred documents |
Automatically created indexes for optimal performance:
Users Collection:
-
{ email: 1 }
(unique) -
{ uid: 1 }
(unique) { createdAt: 1 }
Documents Collection:
{ userId: 1 }
-
{ title: 'text', content: 'text' }
(full-text search) { createdAt: -1 }
Sessions Collection:
-
{ sessionId: 1 }
(unique) { userId: 1 }
-
{ expiresAt: 1 }
(TTL index)
import { connectToDatabase } from './config/database.js';
// Connect with default settings
await connectToDatabase();
// Connect with custom URI
await connectToDatabase('mongodb+srv://custom-uri');
import { dbState } from './config/database.js';
console.log(dbState.isConnected); // Boolean
console.log(dbState.error); // Last error (if any)
console.log(dbState.retryAttempts); // Number of retry attempts
import { checkDatabaseHealth } from './config/database.js';
const health = await checkDatabaseHealth();
console.log(health.status); // 'connected' | 'disconnected' | 'error'
import Document from './models/Document.js';
const document = new Document({
userId: user._id,
title: 'My Wiki Page',
description: 'A sample wiki page',
tags: ['sample', 'wiki'],
markdown: '# Hello World\n\nThis is content.'
});
await document.save();
// Find all documents for a user
const userDocs = await Document.find({ userId: user._id });
// Find with pagination
const docs = await Document
.find()
.skip(page * limit)
.limit(limit)
.sort({ createdAt: -1 });
// Text search
const searchResults = await Document.find({
$text: { $search: 'search terms' }
});
// Update single document
await Document.findByIdAndUpdate(docId, {
title: 'Updated Title',
updatedAt: new Date()
});
// Update multiple documents
await Document.updateMany(
{ userId: user._id },
{ $set: { updatedAt: new Date() } }
);
// Delete single document
await Document.findByIdAndDelete(docId);
// Delete multiple documents
await Document.deleteMany({ userId: user._id });
const stats = await Document.aggregate([
{
$match: { userId: user._id }
},
{
$group: {
_id: null,
totalDocs: { $sum: 1 },
avgTags: { $avg: { $size: '$tags' } }
}
}
]);
const document = await Document
.findById(docId)
.populate('userId', 'displayName email')
.populate('categoryIds', 'name slug')
.populate({
path: 'versionHistory',
select: 'createdAt createdBy reason',
options: { sort: { createdAt: -1 }, limit: 10 }
});
import mongoose from 'mongoose';
const session = await mongoose.startSession();
try {
await session.withTransaction(async () => {
// Create document
const document = new Document({ /* data */ });
await document.save({ session });
// Create initial version
const version = new Version({
documentId: document._id,
/* other data */
});
await version.save({ session });
// Update document with version reference
document.currentVersionId = version._id;
await document.save({ session });
});
} finally {
await session.endSession();
}
import { connectToDatabase } from './config/database.js';
import { logger } from './middleware/logger.js';
try {
await connectToDatabase();
} catch (error) {
logger.error('Database connection failed', {
error: error.message,
code: error.code
});
process.exit(1);
}
try {
const document = await Document.findById(docId);
if (!document) {
throw new NotFoundError('Document not found');
}
} catch (error) {
if (error instanceof mongoose.Error.ValidationError) {
// Handle validation errors
logger.error('Validation error', { errors: error.errors });
} else if (error instanceof mongoose.Error.CastError) {
// Handle invalid ObjectId
logger.error('Invalid document ID', { id: docId });
} else {
// Handle other errors
logger.error('Database operation failed', { error: error.message });
}
throw error;
}
- Use Indexes: Ensure queries use appropriate indexes
-
Limit Fields: Use
.select()
to fetch only needed fields - Pagination: Implement proper pagination for large datasets
- Aggregation: Use aggregation pipeline for complex queries
// Optimized query example
const documents = await Document
.find({ userId: user._id, published: true })
.select('title description createdAt tags')
.sort({ createdAt: -1 })
.limit(20)
.lean(); // Returns plain objects instead of Mongoose documents
-
Connection Pooling: Configured with
maxPoolSize: 10
- Connection Reuse: Single connection instance across application
- Idle Timeout: Automatic cleanup of idle connections
- Write Concerns: Balanced consistency and performance
import { getDatabaseStats } from './config/database.js';
const stats = await getDatabaseStats();
console.log({
collections: stats.collections,
dataSize: stats.dataSize,
storageSize: stats.storageSize,
objects: stats.objects
});
The database configuration includes automatic monitoring:
- Connection state tracking
- Error logging
- Retry attempt counting
- Performance metrics
import { backupDatabase } from './config/database.js';
// Create backup
const backupPath = await backupDatabase('./backups/');
console.log(`Backup created: ${backupPath}`);
MongoDB Atlas provides automatic backup features:
- Continuous Backup: Point-in-time recovery
- Snapshot Backup: Scheduled snapshots
- Cross-Region Backup: Geographic redundancy
- Atlas Dashboard: Use MongoDB Atlas interface for restores
- mongorestore: Command-line tool for local restores
- Application-level: Custom restore logic for specific data
- TLS/SSL: All connections encrypted by default
- Authentication: Database user credentials required
- Network Access: IP whitelisting in Atlas
- Connection String: Secure credential storage
- Field Validation: Mongoose schema validation
- Input Sanitization: Prevent injection attacks
- Access Control: User-based permissions
- Audit Logging: Track data access and changes
Error: Server selection timed out after 30000 ms
Solutions:
- Check network connectivity
- Verify Atlas IP whitelist
- Increase
serverSelectionTimeoutMS
Error: Authentication failed
Solutions:
- Verify username/password
- Check database user permissions
- Ensure correct database name
Error: Allocation failed - JavaScript heap out of memory
Solutions:
- Implement pagination
- Use
.lean()
for read-only operations - Limit result set sizes
# Enable debug logging
DEBUG=mongoose:*
LOG_LEVEL=debug
- MongoDB Atlas Monitoring: Built-in performance monitoring
- Application Logs: Winston-based structured logging
- Health Checks: Automated connection health verification
- Normalize vs Denormalize: Balance based on read/write patterns
- Embed vs Reference: Consider document size and update frequency
- Index Strategy: Create indexes based on query patterns
- Data Types: Use appropriate MongoDB data types
- Avoid Large Documents: Keep documents under 16MB
- Batch Operations: Use bulk operations for multiple changes
- Connection Management: Reuse connections across requests
- Error Handling: Implement comprehensive error handling
- Schema Migration: Use migration scripts for schema changes
- Seed Data: Automated data seeding for development
- Testing: Use separate test databases
- Documentation: Keep schema documentation updated
GET /api/health
Returns database connection status and basic statistics.
GET /api/admin/database/stats
Returns detailed database statistics for administrators.
-
Export Data: Use
mongodump
to export local data - Create Atlas Cluster: Set up MongoDB Atlas cluster
-
Import Data: Use
mongorestore
or Atlas migration tools - Update Configuration: Change connection string
- Test Connection: Verify application connectivity
- Create Migration Script: Write migration logic
- Backup Database: Always backup before migrations
- Test Migration: Run on development environment first
- Apply Migration: Execute on production during maintenance window
- Verify Results: Confirm migration success
This documentation provides comprehensive coverage of MongoDB usage in the wiki-ai project, from basic setup to advanced operations and troubleshooting.