MongoDB Atlas mit Claude Code: NoSQL-Datenbankzugriff 2026

MongoDB Atlas hat sich als die führende Cloud-Datenbankplattform für dokumentenorientierte NoSQL-Workloads etabliert. Mit Claude Code als KI-gestütztem Entwicklungsassistenten lässt sich der gesamte Zyklus — von der Schemaplanung über CRUD-Operationen bis hin zu Aggregation Pipelines und Vector Search für RAG — erheblich beschleunigen.

In diesem Artikel zeigen wir, wie du MongoDB Atlas zusammen mit TypeScript und Claude Code produktiv nutzt. Alle Code-Beispiele folgen den Best Practices 2026: typsichere Interfaces, Zod-Validierung, Connection Pooling und Atlas-spezifische Features wie Vector Search und Full-Text Search.

Was du in diesem Artikel lernst:
  • TypeScript-Client mit MongoClient und typisierten Collections
  • CRUD-Operationen mit Zod-Schema-Validierung
  • Aggregation Pipeline für SaaS-Analytics
  • Atlas Search & Full-Text Search mit $search-Operator
  • Atlas Vector Search für RAG-Pipelines
  • Transactions, Performance-Tuning und Index-Strategien

1. MongoDB Atlas Setup & TypeScript-Client

Setup MongoClient TypeScript

Bevor du Code schreibst, richtest du einen Atlas-Cluster ein. Claude Code hilft dir dabei mit einem einfachen Prompt: "Erstelle mir ein vollständiges MongoDB Atlas TypeScript Setup mit Connection Pooling, Environment-Variablen und typisierten Collection-Interfaces." Die Antwort liefert sofort einen produktionsreifen Boilerplate.

Installation der Abhängigkeiten

# Projektinitialisierung npm init -y npm install mongodb zod dotenv npm install -D typescript @types/node ts-node tsx # tsconfig.json erstellen npx tsc --init --target ES2022 --module NodeNext --strict true

Umgebungsvariablen (.env)

# .env MONGODB_URI="mongodb+srv://username:password@cluster0.abc12.mongodb.net/?retryWrites=true&w=majority" MONGODB_DB_NAME="saas_prod" MONGODB_MAX_POOL_SIZE="20" OPENAI_API_KEY="sk-..."

TypeScript-Interfaces & typisierter Client

// src/db/types.ts import { ObjectId } from 'mongodb'; export interface User { _id?: ObjectId; email: string; name: string; plan: 'free' | 'pro' | 'enterprise'; createdAt: Date; metadata: Record<string, unknown>; } export interface Project { _id?: ObjectId; userId: ObjectId; name: string; description: string; tags: string[]; embedding?: number[]; // für Vector Search createdAt: Date; updatedAt: Date; } export interface Event { _id?: ObjectId; userId: ObjectId; projectId: ObjectId; type: string; payload: Record<string, unknown>; timestamp: Date; }
// src/db/client.ts import { MongoClient, Db, Collection, ServerApiVersion } from 'mongodb'; import 'dotenv/config'; import type { User, Project, Event } from './types.js'; const uri = process.env.MONGODB_URI!; const dbName = process.env.MONGODB_DB_NAME ?? 'saas_prod'; // Singleton-Pattern für Connection Pooling let client: MongoClient | null = null; let db: Db | null = null; export async function getDb(): Promise<Db> { if (db) return db; client = new MongoClient(uri, { serverApi: { version: ServerApiVersion.v1, strict: true, deprecationErrors: true, }, maxPoolSize: parseInt(process.env.MONGODB_MAX_POOL_SIZE ?? '20'), minPoolSize: 5, maxIdleTimeMS: 30_000, connectTimeoutMS: 10_000, socketTimeoutMS: 45_000, }); await client.connect(); db = client.db(dbName); console.log(`✅ MongoDB verbunden: ${dbName}`); return db; } export async function getCollections() { const database = await getDb(); return { users: database.collection<User>('users'), projects: database.collection<Project>('projects'), events: database.collection<Event>('events'), }; } export async function closeDb(): Promise<void> { if (client) { await client.close(); client = null; db = null; } }
Claude Code Tipp: Gib Claude deinen Connection-String und schreibe: "Optimiere diesen MongoClient für Production mit sinnvollem Pooling und Timeout-Werten." Claude kennt die Atlas-spezifischen Empfehlungen und passt die Werte automatisch an deinen Workload an.

2. CRUD-Operationen & Schema-Validierung

CRUD Zod Validation

Mit TypeScript und Zod erhältst du doppelte Sicherheit: Compile-Time-Typen durch die MongoDB-Collection-Generics und Runtime-Validierung durch Zod-Schemas. Claude Code generiert beide Schichten auf einmal, wenn du das gewünschte Datenschema beschreibst.

Zod-Schema-Definition

// src/db/schemas.ts import { z } from 'zod'; export const UserSchema = z.object({ email: z.string().email('Ungültige E-Mail-Adresse'), name: z.string().min(2).max(80), plan: z.enum(['free', 'pro', 'enterprise']).default('free'), metadata: z.record(z.unknown()).default({}), }); export const ProjectSchema = z.object({ name: z.string().min(3).max(120), description: z.string().max(2000).default(''), tags: z.array(z.string()).max(10).default([]), }); export type UserInput = z.infer<typeof UserSchema>; export type ProjectInput = z.infer<typeof ProjectSchema>;

Repository-Pattern für CRUD

// src/db/userRepository.ts import { ObjectId, Filter, UpdateFilter } from 'mongodb'; import { getCollections } from './client.js'; import { UserSchema, type UserInput } from './schemas.js'; import type { User } from './types.js'; export async function createUser(input: UserInput): Promise<User> { // 1. Runtime-Validierung const parsed = UserSchema.parse(input); const { users } = await getCollections(); // 2. Duplikat-Check const existing = await users.findOne({ email: parsed.email }); if (existing) throw new Error(`User mit ${parsed.email} existiert bereits`); // 3. Einfügen mit Timestamps const doc: User = { ...parsed, createdAt: new Date(), }; const result = await users.insertOne(doc); return { ...doc, _id: result.insertedId }; } export async function createManyUsers(inputs: UserInput[]): Promise<number> { const parsed = inputs.map(i => UserSchema.parse(i)); const { users } = await getCollections(); const docs: User[] = parsed.map(p => ({ ...p, createdAt: new Date(), })); const result = await users.insertMany(docs, { ordered: false }); return result.insertedCount; } export async function findUserByEmail(email: string): Promise<User | null> { const { users } = await getCollections(); return users.findOne({ email }); } export async function findUsers( filter: Filter<User> = {}, limit = 50, skip = 0 ): Promise<User[]> { const { users } = await getCollections(); return users .find(filter) .sort({ createdAt: -1 }) .skip(skip) .limit(limit) .toArray(); } export async function updateUserPlan( userId: string, plan: User['plan'] ): Promise<boolean> { const { users } = await getCollections(); const update: UpdateFilter<User> = { $set: { plan }, }; const result = await users.updateOne( { _id: new ObjectId(userId) }, update ); return result.modifiedCount === 1; } export async function deleteInactiveUsers( olderThanDays: number ): Promise<number> { const { users } = await getCollections(); const cutoff = new Date( Date.now() - olderThanDays * 24 * 60 * 60 * 1000 ); const result = await users.deleteMany({ plan: 'free', createdAt: { $lt: cutoff }, }); return result.deletedCount; }
Achtung bei ordered: false: Bei insertMany mit ordered: false werden Duplikate einzeln abgelehnt, aber valide Dokumente trotzdem eingefügt. Prüfe immer das insertedCount-Ergebnis gegen die Eingabelänge.

3. Aggregation Pipeline

Aggregation $lookup $facet

Die Aggregation Pipeline ist eines der mächtigsten Features von MongoDB. Claude Code kann komplexe Pipelines aus natürlicher Sprache generieren. Probiere: "Schreibe mir eine MongoDB Aggregation Pipeline, die den monatlichen Revenue pro Plan-Typ berechnet und nach Top-10-Usern aufschlüsselt."

SaaS Analytics: Monatliche Nutzungsstatistik

// src/analytics/usageStats.ts import { getDb } from '../db/client.js'; export interface MonthlyStats { _id: { year: number; month: number; plan: string }; totalEvents: number; uniqueUsers: number; avgEventsPerUser: number; } export async function getMonthlyUsageStats( months = 6 ): Promise<MonthlyStats[]> { const db = await getDb(); const since = new Date(); since.setMonth(since.getMonth() - months); return db.collection('events').aggregate<MonthlyStats>([ // Stage 1: Zeitraum filtern { $match: { timestamp: { $gte: since }, type: { $in: ['page_view', 'api_call', 'export'] }, }, }, // Stage 2: User-Daten joinen { $lookup: { from: 'users', localField: 'userId', foreignField: '_id', as: 'user', pipeline: [{ $project: { plan: 1, _id: 0 } }], }, }, { $unwind: '$user' }, // Stage 3: Nach Monat + Plan gruppieren { $group: { _id: { year: { $year: '$timestamp' }, month: { $month: '$timestamp' }, plan: '$user.plan', }, totalEvents: { $sum: 1 }, uniqueUsers: { $addToSet: '$userId' }, }, }, // Stage 4: Berechnete Felder { $project: { totalEvents: 1, uniqueUsers: { $size: '$uniqueUsers' }, avgEventsPerUser: { $divide: ['$totalEvents', { $size: '$uniqueUsers' }], }, }, }, // Stage 5: Sortierung { $sort: { '_id.year': -1, '_id.month': -1 } }, ]).toArray(); }

Faceted Search mit $facet

// src/analytics/projectFacets.ts — Multi-Bucket-Analyse export async function getProjectFacets() { const db = await getDb(); const [result] = await db.collection('projects').aggregate([ { $facet: { // Bucket 1: Anzahl Projekte pro Plan-Typ byPlan: [ { $lookup: { from: 'users', localField: 'userId', foreignField: '_id', as: 'owner' } }, { $unwind: '$owner' }, { $group: { _id: '$owner.plan', count: { $sum: 1 } } }, { $sort: { count: -1 } }, ], // Bucket 2: Top-10 meistgenutzte Tags topTags: [ { $unwind: '$tags' }, { $group: { _id: '$tags', count: { $sum: 1 } } }, { $sort: { count: -1 } }, { $limit: 10 }, ], // Bucket 3: Projekte erstellt in letzten 30 Tagen recentActivity: [ { $match: { createdAt: { $gte: new Date(Date.now() - 30 * 86400_000) } } }, { $count: 'total' }, ], }, }, ]).toArray(); return result; }
Claude Code Workflow: Beschreibe dein Analytics-Ziel in Deutsch: "Ich brauche eine Pipeline die mir zeigt, welche User-Kohorten (nach Anmeldemonat) die höchste 30-Tage-Retention haben." Claude baut die komplette Pipeline mit $dateToString, $group und $cond.

4. Atlas Search & Full-Text Search

Atlas Search $search Fuzzy

Atlas Search basiert auf Apache Lucene und ist direkt in MongoDB Atlas integriert. Im Gegensatz zu regulären MongoDB-Queries unterstützt Atlas Search Relevanz-Ranking, Fuzzy-Matching, Highlighting und komplexe Compound-Queries — alles ohne externe Elasticsearch-Instanz.

Search-Index programmatisch erstellen

// src/search/createIndex.ts import { getDb } from '../db/client.js'; export async function createProjectSearchIndex(): Promise<void> { const db = await getDb(); const collection = db.collection('projects'); await collection.createSearchIndex({ name: 'projects_search', definition: { mappings: { dynamic: false, fields: { name: { type: 'string', analyzer: 'lucene.german', // Deutsch-Stemming! searchAnalyzer: 'lucene.german', }, description: { type: 'string', analyzer: 'lucene.german', }, tags: { type: 'string', analyzer: 'lucene.keyword', }, createdAt: { type: 'date', }, }, }, }, }); console.log('✅ Atlas Search Index erstellt'); }

Compound Query mit Fuzzy-Matching und Highlighting

// src/search/projectSearch.ts import { getDb } from '../db/client.js'; export interface SearchResult { _id: string; name: string; description: string; tags: string[]; score: number; highlights?: { path: string; texts: Array<{ value: string; type: string }> }[]; } export async function searchProjects( query: string, options: { limit?: number; filterTags?: string[]; fuzzy?: boolean; } = {} ): Promise<SearchResult[]> { const db = await getDb(); const { limit = 20, filterTags = [], fuzzy = true } = options; const textClause = fuzzy ? { text: { query, path: ['name', 'description'], fuzzy: { maxEdits: 1, prefixLength: 3 }, score: { boost: { value: 2 } }, }, } : { text: { query, path: ['name', 'description'], }, }; const pipeline: object[] = [ { $search: { index: 'projects_search', compound: { must: [textClause], ...(filterTags.length > 0 && { filter: [ { text: { query: filterTags, path: 'tags', }, }, ], }), }, highlight: { path: ['name', 'description'], maxCharsToExamine: 500, maxNumPassages: 2, }, returnStoredSource: true, }, }, { $project: { name: 1, description: 1, tags: 1, score: { $meta: 'searchScore' }, highlights: { $meta: 'searchHighlights' }, }, }, { $limit: limit }, ]; return db.collection('projects').aggregate<SearchResult>(pipeline).toArray(); }
Praxis-Tipp — Autocomplete: Atlas Search unterstützt auch autocomplete-Queries für Echtzeit-Suchvorschläge. Definiere dazu ein Feld mit type: "autocomplete" im Search-Index und nutze den $search.autocomplete-Operator. Claude Code generiert dir den vollständigen Debounce-Handler für React in Sekunden.

5. Atlas Vector Search & RAG-Pipeline

Vector Search $vectorSearch RAG

Atlas Vector Search verwandelt MongoDB in eine vollständige Vektordatenbank. In Kombination mit OpenAI-Embeddings und Claude Code entsteht eine RAG-Pipeline (Retrieval-Augmented Generation), die kontextbezogene Antworten aus deiner eigenen Wissensbasis generiert.

Vector-Index erstellen

// src/vector/createVectorIndex.ts import { getDb } from '../db/client.js'; export async function createProjectVectorIndex(): Promise<void> { const db = await getDb(); await db.collection('projects').createSearchIndex({ name: 'projects_vector', type: 'vectorSearch', definition: { fields: [ { type: 'vector', path: 'embedding', numDimensions: 1536, // text-embedding-3-small similarity: 'cosine', }, { type: 'filter', // Pre-Filter für Metadata path: 'tags', }, ], }, }); console.log('✅ Vector Search Index erstellt'); }

Embeddings generieren & speichern

// src/vector/embeddings.ts import OpenAI from 'openai'; import { getCollections } from '../db/client.js'; import { ObjectId } from 'mongodb'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); export async function generateEmbedding(text: string): Promise<number[]> { const response = await openai.embeddings.create({ model: 'text-embedding-3-small', input: text.slice(0, 8191), // Token-Limit einhalten encoding_format: 'float', }); return response.data[0].embedding; } export async function embedProject(projectId: string): Promise<void> { const { projects } = await getCollections(); const project = await projects.findOne({ _id: new ObjectId(projectId) }); if (!project) throw new Error('Projekt nicht gefunden'); // Semantisch angereicherten Text erstellen const textForEmbedding = [ `Projekt: ${project.name}`, `Beschreibung: ${project.description}`, `Tags: ${project.tags.join(', ')}`, ].join('\n'); const embedding = await generateEmbedding(textForEmbedding); await projects.updateOne( { _id: project._id }, { $set: { embedding } } ); }

$vectorSearch Operator & RAG-Pipeline

// src/vector/ragSearch.ts import { getDb } from '../db/client.js'; import { generateEmbedding } from './embeddings.js'; import type { Project } from '../db/types.js'; export interface VectorSearchResult extends Project { score: number; } export async function semanticSearch( userQuery: string, options: { limit?: number; numCandidates?: number; filterTags?: string[]; } = {} ): Promise<VectorSearchResult[]> { const db = await getDb(); const { limit = 5, numCandidates = 100, filterTags } = options; // Query in Vektor umwandeln const queryEmbedding = await generateEmbedding(userQuery); const vectorSearchStage: Record<string, unknown> = { $vectorSearch: { index: 'projects_vector', path: 'embedding', queryVector: queryEmbedding, numCandidates, limit, ...(filterTags && filterTags.length > 0 && { filter: { tags: { $in: filterTags } }, }), }, }; const results = await db.collection('projects').aggregate<VectorSearchResult>([ vectorSearchStage, { $project: { embedding: 0, // Vektor nicht zurückgeben (1536 Floats = teuer!) score: { $meta: 'vectorSearchScore' }, }, }, ]).toArray(); return results; } // Vollständige RAG-Funktion export async function ragAnswer(question: string): Promise<string> { // 1. Relevante Dokumente aus MongoDB holen const docs = await semanticSearch(question, { limit: 3 }); if (docs.length === 0) { return 'Keine relevanten Projekte gefunden.'; } // 2. Kontext aus Dokumenten aufbauen const context = docs .map((d, i) => `[${i + 1}] ${d.name}: ${d.description}`) .join('\n\n'); // 3. Anthropic API für Antwortgenerierung const Anthropic = (await import('@anthropic-ai/sdk')).default; const anthropic = new Anthropic(); const message = await anthropic.messages.create({ model: 'claude-opus-4-5', max_tokens: 1024, messages: [ { role: 'user', content: `Kontext aus unserer Projektdatenbank:\n\n${context}\n\nFrage: ${question}\n\nAntworte basierend auf dem Kontext auf Deutsch.`, }, ], }); return (message.content[0] as { type: string; text: string }).text; }
Hybrid Search: Kombiniere $vectorSearch (semantisch) mit $search (Keyword) via Reciprocal Rank Fusion (RRF). Claude Code baut dir die RRF-Implementierung auf Anfrage: "Implementiere Hybrid Search in MongoDB mit Vektor + BM25-Ranking."

6. Transactions & Performance-Tuning

Transactions Performance Index

MongoDB unterstützt ACID-Transaktionen über Replica Sets und Sharded Clusters. Atlas-Cluster sind immer Replica Sets, du kannst also sofort Transaktionen nutzen. Für Performance-Tuning bietet Atlas den Performance Advisor und den Profiler — beide lassen sich programmatisch auslesen.

ACID-Transaktionen mit withTransaction

// src/transactions/planUpgrade.ts import { ClientSession } from 'mongodb'; import { getDb } from '../db/client.js'; export interface UpgradeResult { success: boolean; invoiceId?: string; error?: string; } export async function upgradePlan( userId: string, newPlan: 'pro' | 'enterprise', paymentMethodId: string ): Promise<UpgradeResult> { const db = await getDb(); const session = db.client.startSession(); try { let invoiceId: string | undefined; await session.withTransaction(async () => { // 1. User-Plan aktualisieren const userResult = await db.collection('users').updateOne( { _id: userId }, { $set: { plan: newPlan, planUpdatedAt: new Date(), }, }, { session } ); if (userResult.matchedCount === 0) { throw new Error('User nicht gefunden'); } // 2. Rechnung erstellen (gleiche Transaktion!) const invoice = { userId, plan: newPlan, amount: newPlan === 'pro' ? 2900 : 9900, // Cent currency: 'eur', paymentMethodId, status: 'pending', createdAt: new Date(), }; const invoiceResult = await db.collection('invoices').insertOne( invoice, { session } ); invoiceId = invoiceResult.insertedId.toHexString(); // 3. Audit-Log Eintrag await db.collection('audit_logs').insertOne( { action: 'plan_upgrade', userId, newPlan, invoiceId, timestamp: new Date(), }, { session } ); }, { // Transaktion-Optionen readPreference: 'primary', readConcern: { level: 'majority' }, writeConcern: { w: 'majority', j: true }, }); return { success: true, invoiceId }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unbekannter Fehler', }; } finally { await session.endSession(); } }

Index-Strategien & explain()

// src/performance/indexManagement.ts import { getDb } from '../db/client.js'; export async function createOptimalIndexes(): Promise<void> { const db = await getDb(); // Compound Index für häufige Query-Pattern await db.collection('events').createIndex( { userId: 1, timestamp: -1, type: 1 }, { name: 'events_user_time_type', background: true } ); // Sparse Index für optionale Felder await db.collection('projects').createIndex( { embedding: 1 }, { name: 'projects_embedding_sparse', sparse: true } ); // TTL-Index für temporäre Sessions await db.collection('sessions').createIndex( { expiresAt: 1 }, { expireAfterSeconds: 0 } // Atlas löscht Docs wenn expiresAt < now() ); // Text-Index Fallback (ohne Atlas Search) await db.collection('projects').createIndex( { name: 'text', description: 'text' }, { name: 'projects_text', default_language: 'german' } ); console.log('✅ Alle Indexes erstellt'); } export async function analyzeQueryPlan( collectionName: string, filter: object ): Promise<void> { const db = await getDb(); const collection = db.collection(collectionName); const explanation = await collection .find(filter) .explain('executionStats'); const stats = explanation.executionStats; console.log({ winningPlan: explanation.queryPlanner.winningPlan.stage, docsExamined: stats.totalDocsExamined, keysExamined: stats.totalKeysExamined, executionTimeMs: stats.executionTimeMillis, docsReturned: stats.nReturned, // Ratio > 10 → Index fehlt oder suboptimal! examineRatio: stats.totalDocsExamined / (stats.nReturned || 1), }); }

Atlas Profiler: Slow Queries auslesen

// src/performance/profiler.ts — Slow Queries aus system.profile lesen export async function getSlowQueries( thresholdMs = 100, limit = 20 ) { const db = await getDb(); // Profiler-Level auf 1 setzen (nur slow queries loggen) await db.command({ profile: 1, slowms: thresholdMs }); return db.collection('system.profile').find( { millis: { $gte: thresholdMs } }, { projection: { op: 1, ns: 1, millis: 1, ts: 1, keysExamined: 1, docsExamined: 1, nreturned: 1, planSummary: 1, }, } ) .sort({ millis: -1 }) .limit(limit) .toArray(); }
Transaktion-Limits: MongoDB-Transaktionen haben ein 60-Sekunden-Limit und ein 16MB-Dokument-Limit. Für große Bulk-Operationen ist bulkWrite() ohne Transaktion oft schneller. Nutze Transaktionen gezielt für kritische Konsistenz-Anforderungen (Billing, Inventar, Berechtigungsänderungen).

Fazit: MongoDB Atlas + Claude Code = Produktiver Datenbankzugriff

Die Kombination aus MongoDB Atlas und Claude Code deckt den kompletten Datenbankzyklus ab. Claude generiert typsichere Interfaces, Zod-Schemas und komplexe Aggregation Pipelines aus natürlicher Sprache. Für Vector Search und RAG-Pipelines ist MongoDB Atlas 2026 eine ernstzunehmende Alternative zu spezialisierten Vektordatenbanken wie Pinecone oder Weaviate — besonders wenn du ohnehin MongoDB als primäre Datenbank nutzt.

Wichtigste Erkenntnisse:
  1. Connection Pooling: Singleton-Pattern mit maxPoolSize: 20, minPoolSize: 5 für Production
  2. Type Safety: Collection-Generics + Zod = doppelte Sicherheit zur Compile- und Runtime
  3. Aggregation Pipeline: $lookup mit Pipeline-Sub-Query vermeidet Over-Fetching
  4. Atlas Search: Lucene-basiert, deutsch-Stemming, Fuzzy + Highlighting out-of-the-box
  5. Vector Search: Direkt in MongoDB integriert — kein separater Vektorspeicher nötig
  6. Transactions: withTransaction() mit automatischem Retry für kritische Operationen
  7. Performance: explain() + Atlas Profiler identifizieren fehlende Indexes sofort

Claude Code beschleunigt dabei jeden Schritt — von der Index-Definition bis zur vollständigen RAG-Pipeline. Mit dem richtigen Prompt bekommst du in Minuten produktionsreife TypeScript-Implementierungen, die du direkt anpassen und deployen kannst.

MongoDB-Modul im Kurs

Im Claude Code Mastery Kurs: vollständiges MongoDB-Modul mit Aggregation Pipeline, Atlas Search, Vector Search für RAG und Performance-Optimierung.

14 Tage kostenlos testen →