Sources and checks

Add a MongoDB source

Beta

MongoDB support works end to end but is not yet battle-tested across the full version and deployment matrix. Stable today: single-replica-set sources on MongoDB 6 and 7, reachable via mongodb:// or mongodb+srv://. What is rough: Atlas-specific quirks (region transfer limits, IP allowlists), sharded clusters (single-shard only), FLE (field-level encryption) fields. Report edges via simon@hackerman.co.

Point the agent at a MongoDB database. The shape mirrors the Postgres flow: a read role on the source, the URI in an env file, a source block in config.yaml, one check, reload, first backup.

Before you start

  • An agent installed and connected, green dot in the dashboard.
  • A MongoDB 6 or 7 instance (self-hosted or Atlas EU regions).
  • MongoDB Database Tools installed on the agent host. Not in most distro repos; follow MongoDB's install page for your distro. Install the major version matching your source.

1. Create a backup role

The agent calls mongodump. That needs the backup role on the database you are dumping, plus authentication against the admin database where MongoDB stores users by convention.

use admin
db.createUser({
  user: "restorable_backup",
  pwd: "generate-a-strong-one",
  roles: [
    { role: "backup", db: "admin" }
  ]
})

If your source uses client-side field-level encryption, the backup role is not enough to read the encrypted fields; Restorable restores the encrypted blobs as-is and the check sees the ciphertext unless the scratch container has the decryption keys. Plan your checks against the visible fields accordingly, or stage decryption keys into the scratch.

2. Put the URI in the env file

sudo tee -a /var/lib/restorable/env >/dev/null <<'EOF'
RESTORABLE_MONGO_URI=mongodb+srv://restorable_backup:PASSWORD@cluster0.xyz.mongodb.net/?authSource=admin&retryWrites=true&w=majority
EOF

sudo chmod 0600 /var/lib/restorable/env
sudo chown root:root /var/lib/restorable/env

For self-hosted MongoDB, mongodb://user:pass@host:27017/?authSource=admin. Either scheme works with the agent.

3. Declare the source in config.yaml

sources:
  - slug: prod-mongo
    kind: mongodb
    connection:
      uri: env:RESTORABLE_MONGO_URI
    checks:
      - app-healthy

checks:
  - id: app-healthy
    summary_find:
      database: app
      collection: users
      filter: { }
    expect: "n > 0"

The summary_find block is engine-specific to Mongo. It comes in three shapes: filter-with-implicit-count (above), aggregate-pipeline (below), and a list-collections probe that counts user collections in the database (the mongo equivalent of postgres's schema-count check).

Filter form

db.collection.countDocuments(filter), wrapped so the summary row is always { n: <count> }. The expect expression references n.

Aggregate form

checks:
  - id: orders-total
    summary_find:
      database: app
      collection: orders
      aggregate:
        - { $match: { status: "open" } }
        - { $group: { _id: null, n: { $sum: 1 }, total: { $sum: "$amount" } } }
        - { $project: { ok: { $cond: [{ $and: [{ $gt: ["$n", 0] }, { $gt: ["$total", 10000] }] }, 1, 0] } } }
    expect: "ok == 1"

The expect DSL is single-comparison only; compose compound conditions in the pipeline (a final $project with $cond reduces a predicate to a 1/0 column the expect can read).

The first document of the pipeline's result becomes the summary row. Keys in that document are what expect can reference. Aggregate is strictly more powerful than filter; use aggregate when you need more than a count.

List-collections form

checks:
  - id: app-collections
    summary_find:
      database: app
      list_collections: true
    expect: "n >= 4"

Counts user collections in database, dropping names that start with system., and returns { n: <count> }. This is the schema- count probe the wizard auto-attaches as <slug>-collections: it catches the failure mode where a restore exits clean but most of the database didn't materialize (wrong archive, partial restore, role visibility drift). collection, filter, and aggregate must be unset in this mode.

database is required for every shape. The scratch container's default database is admin, which is not where your data lives; name the database explicitly.

4. Reload the agent

sudo systemctl reload restorable.service
sudo journalctl -u restorable.service -f

5. Take the first backup and restore test

From the dashboard, run backup, then run restore test. The flow mirrors Postgres:

  1. Agent runs mongodump --uri=<source> --archive and pipes the archive through age encryption.
  2. Encrypted archive uploads to the ciphertext bucket.
  3. On restore test, the agent downloads and decrypts, spins up a Mongo scratch container matching the source's major version, runs mongorestore, runs the check via the Node driver, signs the receipt.

Common failures

mongodump: not authorized on admin

The role needs { role: "backup", db: "admin" }. Without it, the dump fails on the first collection that requires elevated privileges (config or oplog collections).

Atlas transfer limits

Atlas rate-limits egress on smaller cluster tiers. A large mongodump from an M0 or M2 cluster may throttle or fail after a few GB. For sources that large, move to M10 or host the source elsewhere.

Scratch image missing indexes after restore

mongorestore rebuilds indexes on the scratch by default. On very large collections, index rebuild dominates the restore-test time budget. If that is unacceptable, pass --noIndexRestore via agent config (post-beta feature) and accept that indexed queries in checks will not use their indexes.

SRV record resolution failure

mongodb+srv:// requires DNS SRV records from the agent's host. Corporate DNS that does not forward SRV queries breaks Atlas connectivity. Fall back to the mongodb://host:port/ scheme or fix DNS.

What to write in a Mongo check

Same principles as Writing a check: aim at a specific failure category. A bare countDocuments() catches "restore produced an empty collection" and not much else. Write checks that depend on the schema you care about:

  • A filter matching "recent" documents via $gt: ISODate(...). Catches a stale snapshot.
  • An aggregate summing a numeric field and asserting the total is in a realistic range. Catches a partial restore.
  • A lookup across two collections via $lookup. The Mongo equivalent of a referential-integrity check.