MongoDB: Logical Backup and Restore
Table of Contents
1. What Is a Logical Backup?
A logical backup reads your documents through the database and saves them, with the index definitions, in a format MongoDB can read back. It is not a copy of the files on disk. You use it to move data, restore one collection, or recover from accidental deletes.
| MongoDB | Oracle |
|---|---|
Tool: mongodump (backup) and mongorestore (restore) | Tool: expdp (Data Pump export) and impdp (import) |
| Format: BSON files (binary JSON) + index definitions as JSON | Format: proprietary dump file (.dmp) |
| Runs on the client side and reads data over the network | Runs on the server side and writes to a directory object |
| Works on: standalone, replica set, sharded cluster (a sharded cluster needs a different tool for a consistent backup, see below) | Works on: any Oracle database |
Consistency: --oplog makes a full replica set dump consistent as of the end of the dump. It is not recovery to an arbitrary point in time. | Consistency: FLASHBACK_TIME / FLASHBACK_SCN |
Users and roles: included in a full dump (the admin database). With --db, add --dumpDbUsersAndRoles. | Users, roles and grants: included in full and schema exports |
mongodump --oplog
| 1. note the oplog position (start of dump)
| 2. read every collection --> <coll>.bson + <coll>.metadata.json
| (writes keep happening on the server)
| 3. copy the oplog entries that arrived --> oplog.bson
v
backup folder
mongorestore --oplogReplay
| 1. insert the documents (normal write path: journal + oplog)
| 2. rebuild the indexes (from metadata.json)
| 3. replay oplog.bson --> data consistent as of END of dump
v
restored data
Key points:
•mongodumpandmongorestoreare separate tools you run from the Linux shell, not from inside mongosh. Install them with themongodb-database-toolspackage.
•mongodumpnever dumps thelocaldatabase (the oplog lives there).
• Without--oplog, a dump is not consistent across collections, because writes can happen between reading one collection and the next. This is the same issue asexpdpwithoutflashback_time.
• The dump reads all data through the WiredTiger cache. On a busy server, dump from a secondary if you can.
• Authentication needs a user with the built-inbackuprole (dump) andrestorerole (restore). A restore with--oplogReplaymay need more privileges, so many DBAs use aroot-level user for restores.
2. Backup (mongodump) — Full, Database, Collection
All commands are run from the Linux shell (not mongosh). Replace host, port, username, and paths with your own.
Password on the command line:
--password 'yourpassword'is visible inpsoutput to other users on the server. The examples below use it for clarity. In real use, leave out--password(you will be prompted) or keep the URI in a protected file and use--config.
Full backup (everything except local)
Backs up all databases and collections, including the admin database, so users and roles are included. Use --oplog on a replica set to make the whole dump consistent as of the end of the dump.
# Full backup of everything on the server
mongodump \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--oplog \
--out /backup/mongodb/full_$(date +%Y%m%d_%H%M%S)
# Output goes to:
# /backup/mongodb/full_20250115_103000/
# ├── admin/ (users and roles are here)
# │ ├── system.users.bson
# │ ├── system.roles.bson
# │ └── system.version.bson
# ├── myFirstDB/
# │ ├── students.bson
# │ ├── students.metadata.json
# │ ├── orders.bson
# │ └── orders.metadata.json
# ├── shop/
# │ ├── accounts.bson
# │ └── accounts.metadata.json
# └── oplog.bson (only with --oplog; one file in the top folder)
#
# The local database is never dumped.
About
--oplog:
• It works only for a full dump of a replica set. You cannot combine it with--dbor--collection, and it does not work on a standalone server.
• Use--oplogon dump and--oplogReplayon restore. They go as a pair.
• Sharded clusters: runningmongodump --oplogon each shard separately does not give a consistent cluster backup. Use coordinated snapshots, PBM, Ops Manager, Cloud Manager or Atlas.
Database backup (one database only)
No --oplog here, because it cannot be used with --db.
# Backup only the myFirstDB database
mongodump \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--db myFirstDB \
--out /backup/mongodb/db_myFirstDB_$(date +%Y%m%d_%H%M%S)
# Output:
# /backup/mongodb/db_myFirstDB_20250115_103000/
# └── myFirstDB/
# ├── students.bson
# ├── students.metadata.json
# ├── orders.bson
# └── orders.metadata.json
# To also save the users and roles that belong to this database:
# add --dumpDbUsersAndRoles
Collection backup (one collection only)
# Backup only the students collection
mongodump \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--db myFirstDB \
--collection students \
--out /backup/mongodb/coll_students_$(date +%Y%m%d_%H%M%S)
# Output:
# /backup/mongodb/coll_students_20250115_103000/
# └── myFirstDB/
# ├── students.bson
# └── students.metadata.json
Useful options
| Option | What it does |
|---|---|
--oplog | Captures the oplog so the dump is consistent as of the moment it finished. Full dump of a replica set only. |
--dumpDbUsersAndRoles | With --db, also dumps the users and roles of that database. |
--gzip | Compresses the output files. |
--archive=file.gz | Writes everything to a single file instead of a directory. Cannot be used together with --out. |
--query '{...}' | Backs up only matching documents. Needs --db and --collection. Dates and ObjectIds need extended JSON, for example {"$date": "..."}. |
--excludeCollection=name | Skips a collection (can be used multiple times). |
--readPreference=secondary | Reads from a secondary to avoid load on the primary (replica set only). |
--numParallelCollections=4 | Dumps 4 collections at the same time (4 is the default). |
Users and roles, in one place:
• Full dump (no--db): theadmindatabase is included, so users and roles are in the backup, andmongorestorerestores them.
•--dbdump: users and roles are not included unless you add--dumpDbUsersAndRoles.
• Collection dump: no users or roles.
3. Restore (mongorestore) — Full, Database, Collection
Default behaviour:
mongorestoreonly inserts. If a document with the same_idalready exists, it is reported as a duplicate key error and skipped. Existing documents are not overwritten. Add--dropif you want each collection replaced.
Full restore (everything)
# Restore everything from a full backup
mongorestore \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--oplogReplay \
/backup/mongodb/full_20250115_103000
# --oplogReplay replays oplog.bson to bring the data
# to the point when the dump finished.
# Only use it if the backup was made with --oplog.
To replace what is already there:
mongorestore \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--drop \
--oplogReplay \
/backup/mongodb/full_20250115_103000
# --drop removes each collection that is in the backup before restoring it.
# Collections that are NOT in the backup are left alone.
Database restore (one database only)
# Restore only myFirstDB from a FULL backup
# (do not use --oplogReplay when restoring only part of a full dump)
mongorestore \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--nsInclude "myFirstDB.*" \
/backup/mongodb/full_20250115_103000
# Or restore from a database-level backup:
mongorestore \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
/backup/mongodb/db_myFirstDB_20250115_103000
# If the backup was taken with --dumpDbUsersAndRoles, restore them too:
# --db myFirstDB --restoreDbUsersAndRoles /backup/mongodb/db_myFirstDB_.../myFirstDB
Collection restore (one collection only)
# Restore only the students collection (from a collection backup)
mongorestore \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--nsInclude "myFirstDB.students" \
/backup/mongodb/coll_students_20250115_103000
# Or pick one collection out of a full backup:
mongorestore \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--nsInclude "myFirstDB.students" \
/backup/mongodb/full_20250115_103000
Restore to a different name
# Restore myFirstDB.students as testDB.students_backup
mongorestore \
--host localhost \
--port 27017 \
--username admin \
--password 'yourpassword' \
--authenticationDatabase admin \
--nsInclude "myFirstDB.students" \
--nsFrom "myFirstDB.students" \
--nsTo "testDB.students_backup" \
/backup/mongodb/coll_students_20250115_103000
Useful options
| Option | What it does |
|---|---|
--drop | Drops each collection that is in the backup before restoring it. Use with care. |
--oplogReplay | Replays oplog.bson from a dump made with --oplog. Use it only for a full restore. |
--nsInclude / --nsExclude | Restores only (or skips) matching namespaces, for example "testdb.*" or "testdb.logs". |
--nsFrom / --nsTo | Renames databases or collections during restore. Use together with --nsInclude. |
--gzip | Restores from compressed files. |
--archive=file.gz | Restores from a single archive file. |
--noIndexRestore | Skips index creation (faster load, build indexes later). |
--numParallelCollections=4 | Restores 4 collections at the same time (4 is the default). |
4. Hands-On Practicals
Follow these steps on a test server to see backup and restore in action. Practical 1 assumes a replica set (because of --oplog). On a standalone server, leave out --oplog and --oplogReplay.
Practical 1: Full backup and restore
// Step 1: Create test data in mongosh
use testdb
db.students.insertMany([
{ name: "Ravi", age: 22, grade: "A" },
{ name: "Sita", age: 21, grade: "B" }
])
db.orders.insertMany([
{ item: "laptop", qty: 1 },
{ item: "phone", qty: 2 }
])
db.students.countDocuments() // 2
db.orders.countDocuments() // 2
# Step 2: Backup everything (Linux shell)
mongodump --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--oplog \
--out /backup/full_test
// Step 3: Drop the database in mongosh (simulate data loss)
use testdb
db.dropDatabase()
db.students.countDocuments() // 0 (the collection no longer exists)
# Step 4: Restore everything (Linux shell)
mongorestore --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--oplogReplay \
/backup/full_test
# The admin database is in the backup too. Existing users are skipped
# as duplicates; that is expected.
// Step 5: Verify the data is back in mongosh
use testdb
db.students.countDocuments() // 2
db.orders.countDocuments() // 2
db.students.find()
// Data is restored!
Practical 2: Database backup and restore
# Backup only testdb
mongodump --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--db testdb \
--out /backup/db_testdb
// Delete one collection
use testdb
db.students.drop()
# Restore testdb
mongorestore --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--nsInclude "testdb.*" \
/backup/db_testdb
# students is re-created. orders already exists, so its documents
# are reported as duplicate keys and skipped. Add --drop to replace them instead.
// Verify
use testdb
db.students.countDocuments() // 2
db.orders.countDocuments() // 2
Practical 3: Collection backup and restore
# Backup only the students collection
mongodump --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--db testdb \
--collection students \
--out /backup/coll_students
// Delete one document
use testdb
db.students.deleteOne({ name: "Ravi" })
db.students.countDocuments() // 1
# Restore only the students collection
mongorestore --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--nsInclude "testdb.students" \
--drop \
/backup/coll_students
// Verify
use testdb
db.students.countDocuments() // 2
db.students.find({ name: "Ravi" })
Try without
--drop: run the same restore without--drop. Ravi comes back and Sita is reported as a duplicate key and skipped. This is a handy way to bring back deleted documents without touching the rest.
Practical 4: Restore to a different name
# Restore testdb.students as testdb.students_copy
mongorestore --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--nsInclude "testdb.students" \
--nsFrom "testdb.students" \
--nsTo "testdb.students_copy" \
/backup/coll_students
// Verify both exist
use testdb
db.students.countDocuments() // 2 (original)
db.students_copy.countDocuments() // 2 (copy)
Practical 5: Compressed backup and restore
# Backup with compression into one file
mongodump --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--db testdb \
--gzip \
--archive=/backup/testdb_$(date +%Y%m%d).gz
# Restore from the archive (use the real file name)
mongorestore --host localhost --port 27017 \
--username admin --password 'yourpassword' \
--authenticationDatabase admin \
--gzip \
--archive=/backup/testdb_20250115.gz \
--drop
5. Oracle vs MongoDB Comparison
| Task | MongoDB | Oracle |
|---|---|---|
| Full backup | mongodump --out /backup/full | expdp full=y directory=backup dumpfile=full.dmp |
| Database (schema) backup | mongodump --db myFirstDB | expdp schemas=HR directory=backup dumpfile=hr.dmp |
| Table (collection) backup | mongodump --db myFirstDB --collection students | expdp tables=HR.EMPLOYEES directory=backup dumpfile=emp.dmp |
| Consistent backup | mongodump --oplog (full dump, replica set only) | expdp flashback_time=systimestamp |
| Full restore | mongorestore --oplogReplay /backup/full | impdp full=y directory=backup dumpfile=full.dmp |
| Database restore | mongorestore --nsInclude "myFirstDB.*" /backup/full | impdp schemas=HR directory=backup dumpfile=hr.dmp |
| Table restore | mongorestore --nsInclude "myFirstDB.students" /backup/full | impdp tables=HR.EMPLOYEES directory=backup dumpfile=emp.dmp |
| Restore to different name | mongorestore --nsInclude "db.coll" --nsFrom "db.coll" --nsTo "db.coll_new" | impdp remap_table=HR.EMPLOYEES:EMP_NEW |
| Existing data on restore | Default: duplicate _id skipped. --drop: collection replaced. | table_exists_action=skip|append|truncate|replace |
| Compress backup | --gzip --archive=file.gz | compression=all |
| Includes users and roles? | Full dump: yes (admin database). --db dump: only with --dumpDbUsersAndRoles. | Yes (with full=y or schemas=) |
| Where it runs | Client side, over the network | Server side, into a directory object |
| Output format | BSON files + JSON metadata, or one archive | Proprietary .dmp file |
Bottom line for Oracle DBAs:
•mongodump/mongorestoreare likeexpdp/impdp.
• Use--oplogfor a consistent full dump of a replica set (likeFLASHBACK_TIME). It cannot be combined with--dbor--collection, and it is not recovery to an arbitrary point in time.
• A full dump includes users and roles. A--dbdump needs--dumpDbUsersAndRoles.
•localis never dumped. For sharded clusters, do not rely on per-shard dumps.
• Good for small and medium data and single-collection restores. For large databases, use physical backups.