Problem: catalog with arbitrary attributes "breaks" the relational model
We set up MongoDB for an electronics online store: each category has a unique set of characteristics (diagonal, core count, memory size). In PostgreSQL we would need to build EAV or JSON fields — complex queries and performance degradation with 500 products. MongoDB solved this without pain: the schema is not fixed, and BSON documents fit the product structure perfectly. Our client — a store with 5000 products in 20 categories — got query response times under 10 ms without special optimization. We will tell you how to set up such a database turnkey.
Problems we solve
- N+1 queries when working with documents — a typical mistake when instead of nested arrays, related documents are fetched with separate queries. Solution: use
$lookupin aggregation or store nested subarrays. - Slow writes without replication — when a single node fails, data is lost for minutes. A Replica Set of three servers gives RPO=0 and automatic failover.
- Indexes do not cover queries — without partial and compound indexes, aggregations by status and date take seconds instead of milliseconds. With properly configured indexes, query performance improves 10–100 times.
How we set up MongoDB: Replica Set case
For the same online store, we deployed a cluster on three servers (MongoDB 7.0, Ubuntu 22.04). We configured a Replica Set with two regular nodes and one hidden node for backups. Application connection string: mongodb://myapp:password@mongo1:27017,mongo2:27017/myapp?replicaSet=rs0&readPreference=secondaryPreferred. The result — fault tolerance and read balancing to secondary nodes. A load of 10,000 requests per second is sustained without delays.
Installation and configuration
# Install MongoDB 7.0 curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" > /etc/apt/sources.list.d/mongodb-org-7.0.list apt update && apt install -y mongodb-org systemctl enable mongod && systemctl start mongod # /etc/mongod.conf (main settings) net: port: 27017 bindIp: 127.0.0.1 # for production replace with internal IP security: authorization: enabled storage: dbPath: /var/lib/mongodb wiredTiger: engineConfig: cacheSizeGB: 2 # 50% RAM replication: replSetName: "rs0" operationProfiling: slowOpThresholdMs: 100 mode: slowOp Indexes for typical queries
// Create indexes immediately when designing the schema // Unique index on email db.users.createIndex({ email: 1 }, { unique: true, background: true }) // Compound for sorting user orders db.orders.createIndex({ userId: 1, createdAt: -1 }) // Partial — only active sessions db.sessions.createIndex( { userId: 1, expiresAt: 1 }, { partialFilterExpression: { revokedAt: { $exists: false } } } ) // TTL index — auto-delete logs after 30 days db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 2592000 }) // Text search with Russian language db.articles.createIndex({ title: "text", body: "text" }, { default_language: "russian" }) // Wildcard for catalog with arbitrary attributes db.products.createIndex({ "attributes.$**": 1 }) Aggregation: revenue by category
db.orders.aggregate([ { $match: { createdAt: { $gte: ISODate("2024-01-01"), $lt: ISODate("2024-04-01") }, status: "paid" } }, { $unwind: "$items" }, { $lookup: { from: "products", localField: "items.productId", foreignField: "_id", as: "product" } }, { $unwind: "$product" }, { $group: { _id: "$product.category", revenue: { $sum: { $multiply: ["$items.price", "$items.quantity"] } }, orders: { $addToSet: "$_id" } } }, { $project: { category: "$_id", revenue: { $round: ["$revenue", 2] }, orderCount: { $size: "$orders" } } }, { $sort: { revenue: -1 } } ]) How to choose MongoDB topology for your project?
| Topology | Load | Data volume | Fault tolerance | Administration complexity |
|---|---|---|---|---|
| Single node | up to 10,000 ops/s | up to 100 GB | No | Low |
| Replica Set | up to 50,000 ops/s | up to 10 TB | Automatic failover | Medium |
| Sharded cluster | >50,000 ops/s | >10 TB | High (horizontal scaling) | High |
Why Replica Set is mandatory for production?
Replica Set is the minimum configuration for production. A single node does not provide fault tolerance: if the server fails, data is unavailable until restored. A Replica Set of three nodes guarantees automatic failover to a secondary node within seconds. RPO (recovery point) approaches zero. For most applications this is the optimal balance of reliability and cost. Contact us — we will audit your current schema and suggest the optimal topology.
Process
| Stage | What we do | Duration |
|---|---|---|
| Analysis | Study load, schemas, typical queries. Determine need for sharding. | 1 day |
| Design | Select topology (Replica Set, sharding), server configuration, indexes. | 1 day |
| Implementation | Deploy servers, configure replication, create indexes, write migrations. | 1–3 days |
| Testing | Load testing, failover check, monitoring. | 1 day |
| Deploy | Switch to production, documentation, team training. | 1 day |
What is included
- Server and network configuration (authorization, TLS)
- Replica Set or sharded cluster setup
- Index creation for load (partial, TTL, text)
- Aggregation query optimization
- Integration with Mongoose/Node.js (schemas, hooks, virtuals)
- Monitoring setup (MongoDB Atlas, Prometheus + Grafana)
- Backup (mongodump + automation)
- Documentation and instructions for the team
Typical mistakes when setting up MongoDB
- Missing indexes for sorting —
sort()without an index leads to collection scan (performance collapse). - Ignoring WiredTiger cache size — default 50% RAM, for large working sets you need to increase to 70%.
- Global
uniqueindex on email — blocks registration of same email in different statuses. Use partial indexes. - Writing to a Replica Set without
writeConcern: majority— during primary node rollback data may be lost.
Timeline and cost
Basic setup of a Replica Set with indexes and monitoring — from 2 to 5 days. The cost is calculated individually depending on the schema complexity and number of nodes. Contact us for a project estimate — we will prepare a commercial proposal within one business day. Order MongoDB setup from certified specialists with 10 years of experience.
Why order setup from us?
We are certified MongoDB specialists (over 10 years of experience in NoSQL administration). We have set up more than 50 clusters for projects with loads up to 100,000 requests per second. We provide a warranty on all work — from 3 to 12 months depending on SLA. Get a consultation right now — we will evaluate your current architecture for free.







