Skip to main content

MongoDB on FoundryDB: Aggregation Pipelines, Replica Sets, and Point-in-Time Recovery

· 6 min read
FoundryDB Team
Engineering @ FoundryDB

MongoDB is one of the most popular document databases in the world, but running it in production comes with real operational overhead: replica set initialization, oplog sizing, backup orchestration, WiredTiger cache tuning, and disaster recovery planning. FoundryDB handles all of this out of the box, so you can focus on your application logic.

This post walks through provisioning a MongoDB service, running aggregation pipelines against it, and recovering from data loss using oplog-based point-in-time recovery.

Provision a MongoDB Service

A single API call creates a 3-member replica set with TLS, automated backups, and continuous oplog archiving. No SSH, no config files, no manual rs.initiate().

curl -u $API_KEY:$API_SECRET -X POST \
https://api.foundrydb.com/managed-services \
-H "Content-Type: application/json" \
-d '{
"name": "analytics-mongo",
"database_type": "mongodb",
"version": "8",
"plan_name": "tier-2",
"zone": "se-sto1",
"storage_size_gb": 50,
"storage_tier": "maxiops"
}'

The service transitions from pending through provisioning to running in under five minutes. Once running, connect with the replica set name for full topology awareness:

mongosh "mongodb://USER:PASS@analytics-mongo.db.foundrydb.com:27017/defaultdb?tls=true&replicaSet=rs0"

Every node runs on dedicated infrastructure with a 3-disk architecture: OS disk, NVMe data disk, and a separate backup disk. The data disk uses maxiops storage, which gives consistent low-latency I/O for write-heavy MongoDB workloads.

Replica Set Topology

All MongoDB services on FoundryDB deploy as a 3-member replica set using the rs0 replica set name. The platform handles:

  • Automatic rs.initiate() on the primary during provisioning
  • rs.add() for secondaries using shared keyFile authentication (SCRAM-SHA-1)
  • Automatic failover within approximately 10 seconds if the primary goes down
  • Read preference routing via your driver (secondaryPreferred, nearest)

If you need higher read throughput, scale to a 5-member replica set with one API call:

curl -u $API_KEY:$API_SECRET -X POST \
https://api.foundrydb.com/managed-services/{id}/nodes \
-H "Content-Type: application/json" \
-d '{"role": "replica"}'

You can also trigger a manual failover to a specific secondary for maintenance or testing:

curl -u $API_KEY:$API_SECRET -X POST \
https://api.foundrydb.com/managed-services/{id}/nodes/{node_id}/failover

Aggregation Pipeline Examples

With the service running, let's look at some practical aggregation pipelines. These examples assume you have an orders collection with documents like:

{
"userId": "u_1234",
"items": [
{ "product": "Widget A", "category": "tools", "price": 29.99, "qty": 2 },
{ "product": "Widget B", "category": "parts", "price": 14.50, "qty": 1 }
],
"createdAt": { "$date": "2026-03-15T10:30:00Z" },
"status": "completed"
}

Revenue by Category with $unwind, $group, and $sort

db.orders.aggregate([
{ $match: { status: "completed", createdAt: { $gte: ISODate("2026-01-01") } } },
{ $unwind: "$items" },
{ $group: {
_id: "$items.category",
totalRevenue: { $sum: { $multiply: ["$items.price", "$items.qty"] } },
orderCount: { $sum: 1 },
avgOrderValue: { $avg: { $multiply: ["$items.price", "$items.qty"] } }
}},
{ $sort: { totalRevenue: -1 } },
{ $limit: 10 }
]);

Customer Lifetime Value with $lookup

Join orders with a customers collection to compute per-customer metrics:

db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: {
_id: "$userId",
totalSpent: { $sum: { $sum: "$items.price" } },
orderCount: { $sum: 1 },
lastOrder: { $max: "$createdAt" }
}},
{ $lookup: {
from: "customers",
localField: "_id",
foreignField: "userId",
as: "profile"
}},
{ $unwind: "$profile" },
{ $project: {
name: "$profile.name",
email: "$profile.email",
totalSpent: 1,
orderCount: 1,
lastOrder: 1
}},
{ $sort: { totalSpent: -1 } },
{ $limit: 25 }
]);

Index to Support Your Pipeline

Aggregation pipelines perform best when the $match stage can use an index. Create a compound index that covers the filter:

db.orders.createIndex({ status: 1, createdAt: -1 });

For time-series workloads, a TTL index keeps your collection clean automatically:

db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 86400 });

Oplog-Based Point-in-Time Recovery

Every MongoDB service on FoundryDB gets continuous oplog archiving. The agent tails the local.oplog.rs collection every 5 seconds, batches entries into compressed slices every 10 minutes, encrypts each slice with AES-256-GCM, and uploads to object storage. This runs alongside daily mongodump full backups (with --oplog for consistency).

The PITR window covers 7 days. To check what is available:

curl -u $API_KEY:$API_SECRET \
https://api.foundrydb.com/managed-services/{id}/pitr-range
{
"pitr_enabled": true,
"earliest_recovery_time": "2026-03-30T02:00:00Z",
"latest_recovery_time": "2026-04-06T11:45:00Z",
"retention_days": 7,
"archive_status": "active"
}

Restore Workflow

Imagine someone runs db.orders.drop() at 14:25 UTC. You can restore to 14:24:59, one second before the accident:

curl -u $API_KEY:$API_SECRET -X POST \
https://api.foundrydb.com/managed-services/{id}/backups/restore \
-H "Content-Type: application/json" \
-d '{
"restore_point": "2026-04-06T14:24:59Z",
"target_service_name": "analytics-mongo-restored",
"plan_name": "tier-2",
"zone": "se-sto1"
}'

The restore creates a new service. It never overwrites the source. FoundryDB finds the most recent full backup before your target time, restores it, then replays the archived oplog slices up to the exact timestamp. Monitor progress:

curl -u $API_KEY:$API_SECRET \
https://api.foundrydb.com/managed-services/{restored_service_id}

Restore typically completes in 5 to 30 minutes depending on data size. Once the restored service reaches running status, verify your data, then update your application's connection string or delete the old service.

WiredTiger Cache Tuning

MongoDB uses WiredTiger as its storage engine. By default, FoundryDB configures a 1 GB WiredTiger cache, but you can tune it based on your workload. The wiredTigerCacheSizeGB parameter accepts values from 0.25 GB upward and does not require a restart.

curl -u $API_KEY:$API_SECRET -X PATCH \
https://api.foundrydb.com/managed-services/{id}/configuration \
-H "Content-Type: application/json" \
-d '{
"parameters": {
"wiredTigerCacheSizeGB": "2.5"
}
}'

Other tunable WiredTiger parameters:

ParameterDefaultDescription
wiredTigerCacheSizeGB1Cache size in GB
wiredTigerConcurrentReadTransactions128Max concurrent read tickets (5-128)
wiredTigerConcurrentWriteTransactions128Max concurrent write tickets (5-128)

Monitor WiredTiger cache pressure through the metrics API:

curl -u $API_KEY:$API_SECRET \
"https://api.foundrydb.com/managed-services/{id}/metrics?metric=wiredtiger_cache_used&period=1h"

If cache utilization consistently exceeds 80%, either increase wiredTigerCacheSizeGB or scale your compute plan to a higher tier.

Monitoring Your MongoDB Service

FoundryDB collects MongoDB-specific metrics including connection counts, operation counters (inserts, queries, updates, deletes), replication lag, oplog window size, memory usage, and WiredTiger cache statistics. Enable slow operation profiling to catch inefficient queries:

curl -u $API_KEY:$API_SECRET -X PATCH \
https://api.foundrydb.com/managed-services/{id}/configuration \
-H "Content-Type: application/json" \
-d '{
"parameters": {
"operationProfiling.mode": "slowOp",
"operationProfiling.slowOpThresholdMs": "50"
}
}'

What You Get Without Lifting a Finger

Every MongoDB service on FoundryDB includes:

  • 3-member replica set with automatic failover (approximately 10 seconds)
  • TLS required on all connections
  • Daily automated backups via mongodump --oplog
  • Continuous oplog archiving (every 10 minutes, encrypted with AES-256-GCM)
  • 7-day PITR window for second-level recovery
  • WiredTiger tuning without restarts
  • EU data sovereignty with 5 European zones

MongoDB versions 6, 7, and 8 are all available. Version 8 is recommended for new services.

Get Started

Provision a MongoDB service in under five minutes. Read the MongoDB documentation for connection strings, configuration options, and failover details. Or try it now at foundrydb.com.