Skip to main content
Glama
mongodb.ts7.96 kB
import { MongoClient, Db, Collection, ObjectId, Filter, UpdateFilter } from 'mongodb'; // ============================================ // Configuration // ============================================ const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017'; const dbName = process.env.MONGODB_DB || 'myapp'; let client: MongoClient; let db: Db; export async function connectDB(): Promise<Db> { if (db) return db; client = new MongoClient(uri); await client.connect(); db = client.db(dbName); console.log('Connected to MongoDB'); return db; } export async function disconnectDB(): Promise<void> { if (client) { await client.close(); console.log('Disconnected from MongoDB'); } } // ============================================ // Types // ============================================ export interface BaseDocument { _id?: ObjectId; createdAt?: Date; updatedAt?: Date; } export interface User extends BaseDocument { email: string; name: string; passwordHash: string; role: 'user' | 'admin'; profile?: { avatar?: string; bio?: string; }; } export interface Post extends BaseDocument { authorId: ObjectId; title: string; content: string; tags: string[]; published: boolean; views: number; } // ============================================ // Base Repository // ============================================ export abstract class MongoRepository<T extends BaseDocument> { protected collection!: Collection<T>; constructor(protected collectionName: string) { } protected async getCollection(): Promise<Collection<T>> { if (!this.collection) { const database = await connectDB(); this.collection = database.collection<T>(this.collectionName); } return this.collection; } async findById(id: string | ObjectId): Promise<T | null> { const col = await this.getCollection(); const objectId = typeof id === 'string' ? new ObjectId(id) : id; return col.findOne({ _id: objectId } as Filter<T>); } async findAll(limit = 100, skip = 0): Promise<T[]> { const col = await this.getCollection(); return col.find().sort({ createdAt: -1 }).skip(skip).limit(limit).toArray(); } async create(data: Omit<T, '_id' | 'createdAt' | 'updatedAt'>): Promise<T> { const col = await this.getCollection(); const doc = { ...data, createdAt: new Date(), updatedAt: new Date(), } as T; const result = await col.insertOne(doc as any); return { ...doc, _id: result.insertedId } as T; } async update(id: string | ObjectId, data: Partial<T>): Promise<T | null> { const col = await this.getCollection(); const objectId = typeof id === 'string' ? new ObjectId(id) : id; const updateDoc: UpdateFilter<T> = { $set: { ...data, updatedAt: new Date() } as any }; await col.updateOne({ _id: objectId } as Filter<T>, updateDoc); return this.findById(objectId); } async delete(id: string | ObjectId): Promise<boolean> { const col = await this.getCollection(); const objectId = typeof id === 'string' ? new ObjectId(id) : id; const result = await col.deleteOne({ _id: objectId } as Filter<T>); return result.deletedCount > 0; } async count(filter: Filter<T> = {}): Promise<number> { const col = await this.getCollection(); return col.countDocuments(filter); } } // ============================================ // User Repository // ============================================ export class UserRepository extends MongoRepository<User> { constructor() { super('users'); } async findByEmail(email: string): Promise<User | null> { const col = await this.getCollection(); return col.findOne({ email }); } async findByRole(role: 'user' | 'admin'): Promise<User[]> { const col = await this.getCollection(); return col.find({ role }).toArray(); } async updateProfile(id: string, profile: User['profile']): Promise<User | null> { return this.update(id, { profile } as Partial<User>); } async search(query: string): Promise<User[]> { const col = await this.getCollection(); return col.find({ $or: [ { name: { $regex: query, $options: 'i' } }, { email: { $regex: query, $options: 'i' } } ] }).limit(20).toArray(); } async createIndexes(): Promise<void> { const col = await this.getCollection(); await col.createIndex({ email: 1 }, { unique: true }); await col.createIndex({ name: 'text', email: 'text' }); } } // ============================================ // Post Repository // ============================================ export class PostRepository extends MongoRepository<Post> { constructor() { super('posts'); } async findByAuthor(authorId: string | ObjectId): Promise<Post[]> { const col = await this.getCollection(); const objectId = typeof authorId === 'string' ? new ObjectId(authorId) : authorId; return col.find({ authorId: objectId }).sort({ createdAt: -1 }).toArray(); } async findPublished(limit = 20): Promise<Post[]> { const col = await this.getCollection(); return col.find({ published: true }).sort({ createdAt: -1 }).limit(limit).toArray(); } async findByTag(tag: string): Promise<Post[]> { const col = await this.getCollection(); return col.find({ tags: tag, published: true }).toArray(); } async incrementViews(id: string): Promise<void> { const col = await this.getCollection(); await col.updateOne( { _id: new ObjectId(id) }, { $inc: { views: 1 } } ); } async publish(id: string): Promise<Post | null> { return this.update(id, { published: true }); } async getPopular(limit = 10): Promise<Post[]> { const col = await this.getCollection(); return col.find({ published: true }).sort({ views: -1 }).limit(limit).toArray(); } async createIndexes(): Promise<void> { const col = await this.getCollection(); await col.createIndex({ authorId: 1 }); await col.createIndex({ tags: 1 }); await col.createIndex({ published: 1, createdAt: -1 }); await col.createIndex({ title: 'text', content: 'text' }); } } // ============================================ // Aggregation Examples // ============================================ export async function getPostStats() { const col = (await connectDB()).collection<Post>('posts'); return col.aggregate([ { $group: { _id: '$published', count: { $sum: 1 }, totalViews: { $sum: '$views' }, avgViews: { $avg: '$views' } } } ]).toArray(); } export async function getTopAuthors(limit = 5) { const col = (await connectDB()).collection<Post>('posts'); return col.aggregate([ { $match: { published: true } }, { $group: { _id: '$authorId', postCount: { $sum: 1 }, totalViews: { $sum: '$views' } } }, { $sort: { postCount: -1 } }, { $limit: limit }, { $lookup: { from: 'users', localField: '_id', foreignField: '_id', as: 'author' } }, { $unwind: '$author' } ]).toArray(); } // ============================================ // Exports // ============================================ export const userRepo = new UserRepository(); export const postRepo = new PostRepository();

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/millsydotdev/Code-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server