Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Design MongoDB architectures with document modeling, indexing (ESR rule), sharding, aggregation pipelines, replica sets, and WiredTiger tuning.
.claude/skills/williamzujkowski-mongodb-database-architect/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 111% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 410% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 112% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 471% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 1381% | 0% |
Invoke this skill when designing, reviewing, or optimizing MongoDB database architectures for applications requiring flexible schema, document-based data models, horizontal scalability, or high availability.
Trigger Conditions:
Out of Scope:
NOW_ET using NIST/time.gov semantics (America/New_York, ISO-8601).Abort Conditions:
Use Case: Fast path for common scenarios (80% of requests).
Steps:
{status: "active"}).sort({created_at: -1})){age: {$gt: 18}})db.users.createIndex({status: 1, created_at: -1, age: 1})Output: Schema design decision, 3-5 index recommendations with ESR justification, top 3 bottlenecks.
Use Case: Comprehensive architecture for production deployments.
Steps:
Embedding vs Referencing Table:
| Criteria | Embed | Reference | |----------|-------|-----------| | Relationship | 1-to-1, 1-to-many (low cardinality) | many-to-many, 1-to-many (high cardinality) | | Access Pattern | Always queried together | Often queried independently | | Update Frequency | Infrequent updates | Frequent updates to related data | | Data Growth | Bounded, predictable | Unbounded, grows over time | | Document Size | <16 MB total | Risk of exceeding 16 MB limit | | Atomic Writes | Need atomicity across related data | Atomicity not required |
Schema Validation (MongoDB 8.0):
javascriptdb.createCollection("users", { validator: { $jsonSchema: { bsonType: "object", required: ["email", "created_at"], properties: { email: {bsonType: "string", pattern: "^.+@.+$"}, age: {bsonType: "int", minimum: 0, maximum: 150}, created_at: {bsonType: "date"} } } } })
Index Types and Use Cases:
| Index Type | Use Case | Example | |------------|----------|---------| | Single Field | Equality or range on one field | db.users.createIndex({email: 1}) | | Compound (ESR) | Multi-field queries (Equality, Sort, Range) | db.orders.createIndex({status: 1, created_at: -1, total: 1}) | | Multikey | Arrays (e.g., tags, categories) | db.products.createIndex({tags: 1}) | | Text | Full-text search | db.posts.createIndex({content: "text"}) | | Geospatial | Location-based queries (2dsphere) | db.locations.createIndex({coordinates: "2dsphere"}) | | Hashed | Sharding, equality-only queries | db.sessions.createIndex({session_id: "hashed"}) | | Wildcard | Flexible schema with many fields | db.events.createIndex({"metadata.$**": 1}) | | Partial | Index subset of documents | db.users.createIndex({last_login: 1}, {partialFilterExpression: {active: true}}) |
Covered Query Optimization:
javascript// Covered query: all fields in index, no document access db.orders.createIndex({user_id: 1, status: 1, total: 1}) db.orders.find({user_id: 12345, status: "shipped"}, {_id: 0, user_id: 1, status: 1, total: 1}) // explain() shows: totalDocsExamined: 0 (covered by index)
ESR Rule Application:
javascript// Query: Find active users, sort by created_at descending, filter age > 18 db.users.find({status: "active", age: {$gt: 18}}).sort({created_at: -1}) // Correct index (ESR): // Equality: status (exact match) // Sort: created_at (sort field) // Range: age (range filter) db.users.createIndex({status: 1, created_at: -1, age: 1})
Shard Key Selection (MongoDB 8.0):
| Shard Key Type | Use Case | Pros | Cons | |----------------|----------|------|------| | Hashed | Monotonically increasing IDs, even distribution | Uniform write distribution, no hotspots | Cannot use range queries efficiently on shard key | | Ranged | Time-series data, natural ordering | Efficient range queries, targeted reads | Risk of hotspots if monotonic (e.g., timestamp) | | Compound | Multi-tenant apps, complex access patterns | Balances distribution and query targeting | More complex to design |
Hashed Sharding Example:
javascript// Enable sharding on database sh.enableSharding("myapp") // Shard collection with hashed shard key sh.shardCollection("myapp.users", {user_id: "hashed"}) // MongoDB 8.0: Move unsharded collection to specific shard db.adminCommand({moveCollection: "myapp.analytics", toShard: "shard02"})
Ranged Sharding Example (Time-Series):
javascript// Shard by timestamp for time-series data sh.shardCollection("myapp.events", {timestamp: 1}) // Zone sharding (MongoDB 8.0): Route data by date ranges to specific shards sh.addShardToZone("shard01", "recent") sh.updateZoneKeyRange("myapp.events", {timestamp: ISODate("2025-01-01")}, {timestamp: MaxKey}, "recent")
Avoid Scatter-Gather Queries:
db.users.find({user_id: 12345}) → targets single sharddb.users.find({email: "test@example.com"}) → scatter-gather across all shards (slow)Pipeline Stages (Execution Order Matters):
javascript// Optimized aggregation: $match early, $project late, use indexes db.orders.aggregate([ // Stage 1: $match FIRST (uses index, reduces documents) {$match: {status: "shipped", created_at: {$gte: ISODate("2025-01-01")}}}, // Stage 2: $sort (uses index if compound index exists) {$sort: {created_at: -1}}, // Stage 3: $lookup (join with users collection) {$lookup: { from: "users", localField: "user_id", foreignField: "_id", as: "user_details" }}, // Stage 4: $group (aggregation after filtering) {$group: { _id: "$user_id", total_spent: {$sum: "$total"}, order_count: {$sum: 1} }}, // Stage 5: $project LAST (reduce network transfer) {$project: {_id: 1, total_spent: 1, order_count: 1}} ])
Index Sort Optimization:
{status: 1, created_at: -1} index exists, $match + $sort uses index (no in-memory sort).allowDiskUse: true).Sharded Aggregation (MongoDB 8.0):
$match early to enable shard targeting.Standard 3-Member Replica Set:
javascriptrs.initiate({ _id: "myReplicaSet", members: [ {_id: 0, host: "mongo1.example.com:27017", priority: 2}, // Primary (high priority) {_id: 1, host: "mongo2.example.com:27017", priority: 1}, // Secondary {_id: 2, host: "mongo3.example.com:27017", arbiterOnly: true} // Arbiter (no data) ] })
Read Preferences:
primary (default): All reads from primary (strong consistency).primaryPreferred: Read from primary, fallback to secondary if unavailable.secondary: Read from secondary (may read stale data).secondaryPreferred: Read from secondary, fallback to primary.nearest: Read from lowest-latency member.Write Concerns:
w: 1 (default): Acknowledge after primary write (fast, risk of data loss on primary failure).w: "majority": Acknowledge after majority of replica set members (slower, durable).w: 3: Acknowledge after 3 members (explicit count).j: true: Wait for write to journal (disk) before acknowledging.MongoDB 8.0 Replica Set Enhancements:
WiredTiger Cache Sizing (MongoDB 8.0):
yaml# Default: 50% of RAM - 1 GB storage: wiredTiger: engineConfig: cacheSizeGB: 32 # For 64 GB RAM server (50%)
Guidelines:
db.serverStatus().wiredTiger.cache (bytes in cache, eviction activity).Connection Pool Configuration:
javascript// Application connection string mongodb://mongo1.example.com:27017,mongo2.example.com:27017,mongo3.example.com:27017/?replicaSet=myReplicaSet&maxPoolSize=50&minPoolSize=10&maxIdleTimeMS=60000
Settings:
maxPoolSize: Maximum connections (default 100). Each connection ~1 MB RAM.minPoolSize: Minimum connections (default 0). Pre-warm pool for faster queries.maxIdleTimeMS: Close idle connections after timeout (default: no timeout).Configuration Parameters:
yaml# For 64 GB RAM server (OLTP workload) storage: wiredTiger: engineConfig: cacheSizeGB: 32 # 50% of RAM collectionConfig: blockCompressor: snappy # Default compression indexConfig: prefixCompression: true # Index prefix compression net: maxIncomingConnections: 65536 # Max client connections compression: compressors: snappy # Network compression operationProfiling: mode: slowOp # Profile slow queries slowOpThresholdMs: 100 # Log queries >100ms replication: replSetName: myReplicaSet enableMajorityReadConcern: true # Disable for PSA if cache pressure
MongoDB 8.0 Performance Improvements:
Output: Complete architecture document with schema design, index definitions, sharding strategy, aggregation examples, replica set config, tuning parameters.
Use Case: Multi-region deployments, queryable encryption, sharding at scale, version migrations.
Steps:
javascriptrs.initiate({ _id: "globalReplicaSet", members: [ {_id: 0, host: "us-east-1.example.com:27017", priority: 2, tags: {region: "us-east"}}, {_id: 1, host: "us-east-2.example.com:27017", priority: 1, tags: {region: "us-east"}}, {_id: 2, host: "eu-west-1.example.com:27017", priority: 1, tags: {region: "eu-west"}}, {_id: 3, host: "ap-southeast-1.example.com:27017", priority: 1, tags: {region: "ap-southeast"}}, {_id: 4, host: "arbiter.example.com:27017", arbiterOnly: true} ], settings: { // Read from nearest region getLastErrorDefaults: {w: "majority", wtimeout: 5000} } }) // Region-specific read preferences db.users.find({region: "us-east"}).readPref("nearest", [{region: "us-east"}])
Use Case: Encrypt sensitive fields (PII, PHI) while allowing queries.
javascript// Create encrypted collection (MongoDB 8.0 expanded support) db.createCollection("patients", { encryptedFields: { fields: [ { path: "ssn", bsonType: "string", queries: {queryType: "equality"} // Allow equality queries on encrypted field }, { path: "medical_record", bsonType: "string" // No queries specification = cannot query, only store/retrieve } ] } }) // Query encrypted field db.patients.find({ssn: "123-45-6789"}) // Allowed (queryable encryption)
Parallel Execution on Sharded Cluster:
javascript// Aggregation runs in parallel on each shard, then merges db.orders.aggregate([ {$match: {created_at: {$gte: ISODate("2025-01-01")}}}, // Shard targeting if sharded by created_at {$group: {_id: "$product_id", total_sales: {$sum: "$total"}}}, {$sort: {total_sales: -1}}, {$limit: 10} ], {allowDiskUse: true}) // Allow >100 MB sort for large datasets
Optimization:
$match with date range targets recent shards only.db.currentOp() to see query distribution across shards.Benefits of MongoDB 8.0:
Migration Strategy (Zero-Downtime):
rs.stepDown()) → elect MongoDB 8.0 member as new primary.db.adminCommand({setFeatureCompatibilityVersion: "8.0"}).Risks:
Key Metrics:
javascript// Server status db.serverStatus() // WiredTiger cache stats db.serverStatus().wiredTiger.cache // Monitor: bytes currently in cache, bytes read into cache, eviction activity // Connection stats db.serverStatus().connections // Monitor: current, available, totalCreated // Operation counters db.serverStatus().opcounters // Monitor: insert, query, update, delete, getmore, command // Slow query profiling db.system.profile.find({millis: {$gt: 100}}).sort({ts: -1}).limit(10) // Index usage stats db.collection.aggregate([{$indexStats: {}}])
Tools:
Output: Multi-region architecture, queryable encryption setup, cross-shard aggregation strategy, migration plan with risks, monitoring dashboards.
w: "majority" for critical writes (durability over speed).readPreference: "secondary" for analytics queries (offload primary).$match as early as possible (reduce documents).$match and $sort stages.$project last to reduce network transfer.allowDiskUse: true for >100 MB sorts/groups.Uncertainty Thresholds:
Required Fields:
yamldocument_schema: - collection_name: string embedding_decision: "embed" | "reference" justification: string (why embed or reference) schema_validation: object (JSON schema) sample_document: object indexes: - collection_name: string index_name: string index_definition: object ({field: 1|-1}) index_type: "single" | "compound" | "multikey" | "text" | "geospatial" | "hashed" | "wildcard" | "partial" esr_justification: string (if compound index) estimated_speedup: string (e.g., "50x faster") sharding_strategy: - enabled: boolean shard_key: object ({field: "hashed" | 1}) shard_key_type: "hashed" | "ranged" | "compound" justification: string (why this shard key) target_chunk_size: string (default: "64 MB") aggregation_examples: - use_case: string pipeline: array (aggregation stages) optimization_notes: string replica_set: - members: integer (3, 5, etc.) configuration: object (rs.initiate() config) read_preference: "primary" | "primaryPreferred" | "secondary" | "secondaryPreferred" | "nearest" write_concern: object ({w: "majority", j: true}) performance_tuning: - wiredtiger_cache_gb: number max_connections: integer connection_pool_size: integer profiling_threshold_ms: integer estimated_improvement: string (e.g., "36% faster reads") migration_plan: # If upgrading versions - current_version: string target_version: string strategy: "rolling upgrade" | "blue-green" | "snapshot restore" steps: array (migration steps) risks: array (potential issues) downtime_estimate: string
Token Tier Minimums:
ESR Rule for Compound Index:
javascript// Query: Find active users, sort by created_at descending, filter age > 18 db.users.find({status: "active", age: {$gt: 18}}).sort({created_at: -1}) // Index following ESR rule: // E (Equality): status // S (Sort): created_at // R (Range): age db.users.createIndex({status: 1, created_at: -1, age: 1})
See examples/content-management-mongodb-architecture.txt for a complete architecture example.
Official MongoDB Documentation:
Performance & Best Practices:
Tools:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 8,824 | 9,543 | +8% | 1 | 1 | 0% | 1,773 | 9,047 | +410% | 0 | 0 | — |
case-02 | fail→pass | 28,005 | 23,713 | -15% | 1 | 1 | 0% | 6,240 | 13,163 | +111% | 0 | 0 | — |
case-03 | pass→pass | 27,326 | 25,614 | -6% | 1 | 1 | 0% | 6,258 | 13,239 | +112% | 0 | 0 | — |
case-04 | pass→pass | 5,911 | 5,350 | -9% | 1 | 1 | 0% | 1,414 | 8,075 | +471% | 0 | 0 | — |
case-05 | pass→pass | 2,408 | 2,719 | +13% | 1 | 1 | 0% | 498 | 7,376 | +1381% | 0 | 0 | — |
case-06 | pass→pass | 6,420 | 6,269 | -2% | 1 | 1 | 0% | 1,315 | 8,252 | +528% | 0 | 0 | — |
case-07 | pass→pass | 8,676 | 8,664 | -0% | 1 | 1 | 0% | 1,789 | 8,980 | +402% | 0 | 0 | — |
case-08 | pass→pass | 15,188 | 12,329 | -19% | 1 | 1 | 0% | 3,160 | 9,688 | +207% | 0 | 0 | — |
case-09 | pass→pass | 7,388 | 5,142 | -30% | 1 | 1 | 0% | 1,489 | 8,022 | +439% | 0 | 0 | — |
case-10 | fail→fail | 11,887 | 13,943 | +17% | 1 | 1 | 0% | 2,265 | 9,988 | +341% | 0 | 0 | — |
case-11 | pass→pass | 11,562 | 7,258 | -37% | 1 | 1 | 0% | 2,418 | 8,425 | +248% | 0 | 0 | — |
case-12 | pass→pass | 5,603 | 5,934 | +6% | 1 | 1 | 0% | 1,324 | 8,230 | +522% | 0 | 0 | — |
case-13 | pass→pass | 11,484 | 10,305 | -10% | 1 | 1 | 0% | 2,416 | 8,999 | +272% | 0 | 0 | — |
case-14 | pass→pass | 6,715 | 5,616 | -16% | 1 | 1 | 0% | 1,517 | 8,068 | +432% | 0 | 0 | — |
case-15 | pass→pass | 4,100 | 5,599 | +37% | 1 | 1 | 0% | 786 | 7,983 | +916% | 0 | 0 | — |
case-16 | pass→pass | 3,230 | 3,681 | +14% | 1 | 1 | 0% | 698 | 7,716 | +1005% | 0 | 0 | — |
case-17 | pass→pass | 5,780 | 6,853 | +19% | 1 | 1 | 0% | 1,178 | 8,237 | +599% | 0 | 0 | — |
case-18 | pass→pass | 4,498 | 4,150 | -8% | 1 | 1 | 0% | 890 | 7,839 | +781% | 0 | 0 | — |
case-19 | pass→pass | 7,031 | 5,351 | -24% | 1 | 1 | 0% | 1,126 | 8,024 | +613% | 0 | 0 | — |
case-20 | pass→pass | 5,056 | 7,996 | +58% | 1 | 1 | 0% | 1,066 | 8,382 | +686% | 0 | 0 | — |
case-21 | pass→pass | 7,414 | 6,278 | -15% | 1 | 1 | 0% | 1,511 | 8,212 | +443% | 0 | 0 | — |
case-22 | pass→pass | 6,499 | 6,129 | -6% | 1 | 1 | 0% | 1,409 | 8,262 | +486% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.