Skip to main content

MongoDB

MongoDB

MongoDB is a popular NoSQL document database designed for scalability and developer agility, storing data in flexible JSON-like documents.

Overview​

  • Versions: 8.2, 8.0, 7.0 (default: 8.2)
  • Default Port: 27017
  • Cluster Support: Yes (Replica sets)
  • Use Cases: Document databases, JSON storage, real-time analytics
  • Features: Auto-backups, replica sets, 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
  • 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​

  • Single node deployment for development and testing
  • Lower cost, simpler setup

Cluster (High Availability)​

  • Cluster deployment with multiple nodes for high availability and scalability
  • Data Nodes: replica set members (3-10); every member holds a full copy of the data
  • Replication Factor: the number of copies, which in a replica set is the number of data nodes, so it must equal Data Nodes
  • Enable Arbiter Node: optional arbiter for tie-breaking in elections (it votes but holds no data)
  • The set keeps a primary, and accepts writes, while a majority of its voting members is up

Resources​

Choose the add-on's resources on the create form:

SettingOptionsDefault
CPU (vCPU)Any number of cores, e.g. 0.5, 1, 20.5
MemoryAny amount in GB, at least the type's minimum1 GB
DiskAny amount in GB10 GB
GPU Count0-8 (0 for CPU-only)0

Creating a MongoDB Add-on​

  1. Navigate to Add-ons and click Create Add-on
  2. On the Create New Add-on page, select MongoDB as the type
  3. Choose a version (8.2, 8.0, or 7.0)
  4. Select deployment mode:
    • Single Node: for development/testing
    • Cluster (High Availability): 3-10 data nodes, replication factor equal to the data nodes, optional arbiter
  5. Configure:
    • Add-on Label (required): descriptive name (e.g., "main-database")
    • Description (optional): purpose and notes
    • Resources: CPU, memory, and disk for your workload
  6. Optionally enable automatic backups:
    • Schedule: Hourly, Daily, Weekly, or Monthly
    • Retention: number of backups to keep (1-30, default 7)
  7. Click Create Add-on

Connection Information​

Once the add-on is running, the Connection tab of the add-on details page shows the internal host (for apps), port, database, username, password, and a ready-to-use connection string. The same details are exposed to your apps via STRONGLY_SERVICES.

Connection String Format​

Single Node:

mongodb://username:password@host:27017/admin

Replica Set:

mongodb://username:password@host1:27017,host2:27017,host3:27017/admin?replicaSet=rs0

Credentials are auto-generated during add-on creation. The username is a randomly generated string (e.g., user_a1b2c3d4), and the password is a 32-character random secret. The default database in the connection string is admin.

Accessing Connection Details​

In STRONGLY_SERVICES, add-ons are grouped by type under services.addons, and each entry is one provisioned instance with connection and auth sections:

{
"id": "addon-abc123defg",
"name": "main-database",
"type": "mongodb",
"category": "add-on",
"status": "running",
"version": "8.2",
"connection": {
"connection_string": "mongodb://user_a1b2c3d4:<password>@<internal-host>:27017/admin",
"uri": "mongodb://user_a1b2c3d4:<password>@<internal-host>:27017/admin",
"host": "<internal-host>",
"port": 27017,
"database": "admin"
},
"auth": {
"method": "username_password",
"credentials": { "username": "user_a1b2c3d4", "password": "<password>" }
},
"limits": { "max_connections": 100, "storage_gb": 10 },
"metadata": { "cpu": "0.5", "memory": "1GB", "disk": "10GB", "backup_enabled": false }
}
import os
import json
from pymongo import MongoClient

# Parse STRONGLY_SERVICES
services = json.loads(os.environ['STRONGLY_SERVICES'])

# Pick your MongoDB add-on by name (the label you gave it)
mongodb_addon = next(
a for a in services['services']['addons']['mongodb']
if a['name'] == 'main-database'
)

# Connect using the connection string
client = MongoClient(mongodb_addon['connection']['connection_string'])
db = client[mongodb_addon['connection']['database']]

# Or connect using individual parameters
client = MongoClient(
host=mongodb_addon['connection']['host'],
port=mongodb_addon['connection']['port'],
username=mongodb_addon['auth']['credentials']['username'],
password=mongodb_addon['auth']['credentials']['password']
)
db = client[mongodb_addon['connection']['database']]

# Query documents
users = db.users.find({'active': True})
for user in users:
print(user)

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

Backups​

A MongoDB backup is a mongodump archive of every database (backup.archive); a cluster is dumped from the replica set.

  • Back up now: click Backup Now on the status card, or Back Up Now on the Backup tab, while the add-on is running.

  • Automatic: on the Backup tab turn on Enable Automatic Backups, choose a Backup Schedule (Hourly, Daily, Weekly or Monthly) and a Retention (3, 7, 14 or 30 backups), and click Save Configuration. Older backups beyond the retention count are deleted automatically.

  • History: the Backup tab lists every backup with its status, size and any error.

  • Restore: click Restore next to a succeeded backup in Backup History and confirm. The backup is loaded back into this add-on while it keeps running: every database is dropped and reloaded from the backup. Reads find missing data until the restore finishes. Data written after the backup is lost. See Restoring a backup.

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​

  1. Embed vs Reference: Embed frequently accessed related data, reference rarely accessed data
  2. Avoid Unbounded Arrays: Use references or bucketing for growing arrays
  3. Optimize for Read Patterns: Design schema based on how you query data
  4. 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​

The Metrics tab on the add-on details page measures the running add-on live: CPU, memory and disk use against its size, network traffic, open and new connections, response time, and instance health and uptime. See Metrics. The Logs tab shows its recent log output.

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​

  1. Use Indexes: Index fields used in queries, but avoid over-indexing
  2. Enable Connection Pooling: Reuse connections for better performance
  3. Use Projection: Request only needed fields to reduce network traffic
  4. Backup Regularly: Enable daily backups for production databases
  5. Monitor Performance: Use explain() to analyze slow queries
  6. Schema Design: Design schema for your read/write patterns
  7. Use Transactions Sparingly: Only when ACID guarantees are needed
  8. Avoid Large Documents: Keep documents under 16MB limit
  9. Use Replica Sets: Always use replica sets for production
  10. 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:

RelationalMongoDB
DatabaseDatabase
TableCollection
RowDocument
ColumnField
IndexIndex
JOINEmbedded docs or $lookup
Foreign KeyReference

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 Logs tab of the add-on details page
  • Review MongoDB official documentation
  • Contact Strongly support through the platform