MongoDB
MongoDB is a popular NoSQL document database designed for scalability and developer agility, storing data in flexible JSON-like documents.
Overview
- Versions: 8.0, 7.0, 6.0
- Cluster Support: ✅ Yes (Replica sets and sharding)
- Use Cases: Document databases, JSON storage, real-time analytics
- Features: Auto-backups, replica sets, sharding, aggregation framework
Key Features
- Document-Oriented: Store data as flexible JSON-like documents (BSON)
- Schema Flexibility: No rigid schema required, adapt as your app evolves
- Horizontal Scaling: Built-in sharding for distributing data across nodes
- High Availability: Replica sets with automatic failover
- Rich Query Language: Powerful queries, aggregation framework, and indexes
- ACID Transactions: Multi-document ACID transactions (MongoDB 4.0+)
- GridFS: Store and retrieve large files
- Change Streams: Real-time data change notifications
Deployment Modes
MongoDB supports both single-node and cluster deployments:
Single Node
- Best for development and testing
- Lower cost, simpler setup
- Single point of failure
- Suitable for non-critical workloads
Cluster (Replica Set)
- Recommended for production workloads
- High availability with automatic failover
- 3-10 data nodes configurable
- Optional arbiter node for tie-breaking
- Read scaling with secondary reads
- Zero-downtime maintenance
Resource Tiers
| Tier | CPU | Memory | Disk | Replicas | Best For |
|---|---|---|---|---|---|
| Small | 0.5 | 1GB | 10GB | 1 | Development, testing |
| Medium | 1 | 2GB | 25GB | 1 | Small production apps |
| Large | 2 | 4GB | 50GB | 3 (HA) | Production workloads |
| XLarge | 4 | 8GB | 100GB | 3 (HA) | High-traffic applications |
Creating a MongoDB Add-on
- Navigate to Add-ons → Create Add-on
- Select MongoDB as the type
- Choose a version (8.0, 7.0, or 6.0)
- Select deployment mode:
- Single Node: For development/testing
- Cluster: For production (3-10 nodes + optional arbiter)
- Configure:
- Label: Descriptive name (e.g., "User Data Store")
- Description: Purpose and notes
- Environment: Development or Production
- Resource Tier: Based on your workload requirements
- Configure backups:
- Schedule: Daily recommended for production
- Retention: 7+ days for production
- Click Create Add-on
Connection Information
After deployment, connection details are available in the add-on details page and automatically injected into your apps via STRONGLY_SERVICES.
Connection String Format
Single Node:
mongodb://username:password@host:27017/database
Replica Set:
mongodb://username:password@host1:27017,host2:27017,host3:27017/database?replicaSet=rs0
Accessing Connection Details
- Python
- Node.js
- Go
import os
import json
from pymongo import MongoClient
# Parse STRONGLY_SERVICES
services = json.loads(os.environ.get('STRONGLY_SERVICES', '{}'))
# Get MongoDB add-on connection
mongodb_addon = services['addons']['addon-id']
# Connect using connection string
client = MongoClient(mongodb_addon['connectionString'])
db = client[mongodb_addon['database']]
# Or connect using individual parameters
client = MongoClient(
host=mongodb_addon['host'],
port=mongodb_addon['port'],
username=mongodb_addon['username'],
password=mongodb_addon['password']
)
db = client[mongodb_addon['database']]
# Query documents
users = db.users.find({'active': True})
for user in users:
print(user)
const { MongoClient } = require('mongodb');
// Parse STRONGLY_SERVICES
const services = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
const mongoAddon = services.addons['addon-id'];
// Connect using connection string
const client = new MongoClient(mongoAddon.connectionString);
async function main() {
await client.connect();
const db = client.db(mongoAddon.database);
// Query documents
const users = await db.collection('users').find({ active: true }).toArray();
console.log(users);
await client.close();
}
main().catch(console.error);
package main
import (
"context"
"encoding/json"
"os"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/bson"
)
type Services struct {
Addons map[string]Addon `json:"addons"`
}
type Addon struct {
ConnectionString string `json:"connectionString"`
Database string `json:"database"`
}
type User struct {
Email string `bson:"email"`
Active bool `bson:"active"`
}
func main() {
var services Services
json.Unmarshal([]byte(os.Getenv("STRONGLY_SERVICES")), &services)
mongoAddon := services.Addons["addon-id"]
// Connect using connection string
client, err := mongo.Connect(
context.TODO(),
options.Client().ApplyURI(mongoAddon.ConnectionString),
)
if err != nil {
panic(err)
}
defer client.Disconnect(context.TODO())
// Query documents
db := client.Database(mongoAddon.Database)
collection := db.Collection("users")
var users []User
cursor, err := collection.Find(context.TODO(), bson.M{"active": true})
if err != nil {
panic(err)
}
cursor.All(context.TODO(), &users)
}
Common Operations
Creating Collections and Documents
// Collections are created automatically when you insert documents
db.users.insertOne({
email: 'user@example.com',
username: 'johndoe',
active: true,
profile: {
firstName: 'John',
lastName: 'Doe',
age: 30
},
tags: ['premium', 'verified'],
createdAt: new Date()
});
// Insert multiple documents
db.users.insertMany([
{ email: 'alice@example.com', username: 'alice', active: true },
{ email: 'bob@example.com', username: 'bob', active: false }
]);
Querying Documents
// Find all active users
db.users.find({ active: true });
// Find with nested field
db.users.find({ 'profile.age': { $gte: 25 } });
// Find with array contains
db.users.find({ tags: 'premium' });
// Find with multiple conditions
db.users.find({
active: true,
'profile.age': { $gte: 18, $lte: 65 }
});
// Projection (select specific fields)
db.users.find(
{ active: true },
{ email: 1, username: 1, _id: 0 }
);
// Sort and limit
db.users.find({ active: true })
.sort({ createdAt: -1 })
.limit(10);
Updating Documents
// Update one document
db.users.updateOne(
{ email: 'user@example.com' },
{
$set: { active: false },
$currentDate: { lastModified: true }
}
);
// Update multiple documents
db.users.updateMany(
{ 'profile.age': { $lt: 18 } },
{ $set: { 'profile.minor': true } }
);
// Update with operators
db.users.updateOne(
{ email: 'user@example.com' },
{
$inc: { 'stats.loginCount': 1 },
$push: { tags: 'new-tag' },
$set: { lastLogin: new Date() }
}
);
// Upsert (update or insert)
db.users.updateOne(
{ email: 'newuser@example.com' },
{ $set: { username: 'newuser', active: true } },
{ upsert: true }
);
Deleting Documents
// Delete one document
db.users.deleteOne({ email: 'user@example.com' });
// Delete multiple documents
db.users.deleteMany({ active: false });
// Delete all documents in collection
db.users.deleteMany({});
Indexing
Indexes improve query performance significantly.
// Create single field index
db.users.createIndex({ email: 1 });
// Create compound index
db.users.createIndex({ username: 1, active: 1 });
// Create unique index
db.users.createIndex({ email: 1 }, { unique: true });
// Create text index for full-text search
db.articles.createIndex({ title: 'text', content: 'text' });
// Create TTL index (auto-delete after time)
db.sessions.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 3600 }
);
// Create partial index (index subset of documents)
db.users.createIndex(
{ email: 1 },
{ partialFilterExpression: { active: true } }
);
// List all indexes
db.users.getIndexes();
// Drop index
db.users.dropIndex('email_1');
Aggregation Framework
Powerful data processing and analysis pipeline.
// Basic aggregation
db.orders.aggregate([
{ $match: { status: 'completed' } },
{ $group: {
_id: '$customerId',
totalSpent: { $sum: '$amount' },
orderCount: { $sum: 1 }
}
},
{ $sort: { totalSpent: -1 } },
{ $limit: 10 }
]);
// Complex aggregation with lookup (join)
db.orders.aggregate([
{
$lookup: {
from: 'users',
localField: 'userId',
foreignField: '_id',
as: 'user'
}
},
{ $unwind: '$user' },
{
$project: {
orderDate: 1,
amount: 1,
userName: '$user.username',
userEmail: '$user.email'
}
}
]);
// Aggregation with date operations
db.events.aggregate([
{
$group: {
_id: {
year: { $year: '$timestamp' },
month: { $month: '$timestamp' }
},
count: { $sum: 1 }
}
}
]);
Transactions
Multi-document ACID transactions for data consistency.
from pymongo import MongoClient
client = MongoClient(connection_string)
db = client.database
# Start a session
with client.start_session() as session:
# Start a transaction
with session.start_transaction():
try:
# Multiple operations in transaction
db.accounts.update_one(
{'accountId': 'A'},
{'$inc': {'balance': -100}},
session=session
)
db.accounts.update_one(
{'accountId': 'B'},
{'$inc': {'balance': 100}},
session=session
)
# Transaction commits automatically if no exception
except Exception as e:
# Transaction aborts on exception
print(f"Transaction aborted: {e}")
raise
Backup & Restore
MongoDB add-ons use mongodump for backups, creating complete BSON dumps of your database.
Backup Configuration
- Tool:
mongodump - Format:
.archive - Includes: Full database dump with indexes
- Storage: AWS S3 (
s3://strongly-backups/backups/<addon-id>/)
Manual Backup
- Go to add-on details page
- Click Backup Now
- Monitor progress in job logs
- Backup saved as
backup-YYYYMMDDHHMMSS.archive
Scheduled Backups
Configure during add-on creation or in settings:
- Daily backups: Recommended for production
- Retention: 7-14 days minimum for production
- Custom cron: For specific schedules (e.g.,
0 2 * * *for 2 AM daily)
Restore Process
- Navigate to Backups tab
- Select backup from list
- Click Restore
- Confirm (add-on will stop temporarily)
- Data restored using
mongorestore - Add-on automatically restarts
Restoring from backup replaces ALL current data. Create a current backup first if needed.
Performance Optimization
Connection Pooling
from pymongo import MongoClient
# Connection pooling is automatic, configure pool size
client = MongoClient(
connection_string,
maxPoolSize=50,
minPoolSize=10
)
Query Optimization
// Use explain() to analyze queries
db.users.find({ email: 'user@example.com' }).explain('executionStats');
// Check if index is used
db.users.find({ active: true }).explain('executionStats').executionStats.totalDocsExamined;
// Use projection to reduce data transfer
db.users.find(
{ active: true },
{ email: 1, username: 1 } // Only return these fields
);
// Use covered queries (query satisfied by index alone)
db.users.createIndex({ email: 1, username: 1 });
db.users.find(
{ email: 'user@example.com' },
{ email: 1, username: 1, _id: 0 }
);
Schema Design Best Practices
- Embed vs Reference: Embed frequently accessed related data, reference rarely accessed data
- Avoid Unbounded Arrays: Use references or bucketing for growing arrays
- Optimize for Read Patterns: Design schema based on how you query data
- Use Appropriate Data Types: Use proper types (Date, ObjectId, etc.)
// Good: Embedded document for 1-to-few
{
_id: ObjectId('...'),
username: 'johndoe',
addresses: [
{ street: '123 Main St', city: 'NYC', type: 'home' },
{ street: '456 Work Ave', city: 'NYC', type: 'work' }
]
}
// Good: Reference for 1-to-many
{
_id: ObjectId('...'),
username: 'johndoe',
orderIds: [ObjectId('...'), ObjectId('...')]
}
Monitoring
Monitor your MongoDB add-on through the Strongly platform:
- CPU Usage: Track CPU utilization
- Memory Usage: Monitor memory consumption
- Disk Space: Watch disk utilization
- Connection Count: Active connections
- Operation Performance: Query execution times
- Replica Set Status: Health of cluster nodes (if using cluster mode)
Database Statistics
// Database statistics
db.stats();
// Collection statistics
db.users.stats();
// Server status
db.serverStatus();
// Current operations
db.currentOp();
// Connection statistics
db.serverStatus().connections;
Best Practices
- Use Indexes: Index fields used in queries, but avoid over-indexing
- Enable Connection Pooling: Reuse connections for better performance
- Use Projection: Request only needed fields to reduce network traffic
- Backup Regularly: Enable daily backups for production databases
- Monitor Performance: Use explain() to analyze slow queries
- Schema Design: Design schema for your read/write patterns
- Use Transactions Sparingly: Only when ACID guarantees are needed
- Avoid Large Documents: Keep documents under 16MB limit
- Use Replica Sets: Always use replica sets for production
- Test Restores: Periodically verify backup restoration
- Separate Dev/Prod: Never connect production apps to development databases
- Use Appropriate Write Concerns: Balance between performance and durability
Replica Set Configuration
When using cluster mode, MongoDB automatically configures replica sets:
// Check replica set status
rs.status();
// View replica set configuration
rs.conf();
// Check which node is primary
db.isMaster();
Read Preferences
from pymongo import MongoClient, ReadPreference
# Read from primary only (default, strongest consistency)
client = MongoClient(connection_string)
# Read from secondary when possible (eventual consistency)
client = MongoClient(
connection_string,
readPreference=ReadPreference.SECONDARY_PREFERRED
)
# Read from nearest node (lowest latency)
client = MongoClient(
connection_string,
readPreference=ReadPreference.NEAREST
)
Migration Guide
From Relational Database to MongoDB
Key concepts mapping:
| Relational | MongoDB |
|---|---|
| Database | Database |
| Table | Collection |
| Row | Document |
| Column | Field |
| Index | Index |
| JOIN | Embedded docs or $lookup |
| Foreign Key | Reference |
Example transformation:
-- SQL
SELECT users.username, orders.amount
FROM users
JOIN orders ON users.id = orders.user_id
WHERE users.active = true;
// MongoDB with embedded documents
db.users.find(
{ active: true },
{ username: 1, 'orders.amount': 1 }
);
// MongoDB with $lookup (join)
db.users.aggregate([
{ $match: { active: true } },
{
$lookup: {
from: 'orders',
localField: '_id',
foreignField: 'userId',
as: 'orders'
}
},
{
$project: {
username: 1,
'orders.amount': 1
}
}
]);
Troubleshooting
Connection Issues
// Test connection
const { MongoClient } = require('mongodb');
const client = new MongoClient(connectionString);
await client.connect();
console.log('Connected successfully');
await client.close();
Performance Issues
// Find slow queries
db.system.profile.find({ millis: { $gt: 1000 } }).sort({ ts: -1 }).limit(10);
// Enable profiling to track slow queries
db.setProfilingLevel(1, { slowms: 100 });
// Check current operations
db.currentOp({ 'active': true, 'secs_running': { $gt: 5 } });
// Kill a long-running operation
db.killOp(opId);
Disk Space Issues
// Check database size
db.stats(1024*1024); // Size in MB
// Check collection sizes
db.getCollectionNames().forEach(function(collection) {
var stats = db.getCollection(collection).stats(1024*1024);
print(collection + ': ' + stats.size + ' MB');
});
// Compact collection to reclaim space
db.runCommand({ compact: 'users' });
Support
For issues or questions:
- Check add-on logs in the Strongly dashboard
- Review MongoDB official documentation
- Contact Strongly support through the platform