#Backup and restore
A backup is only as good as the restore you've practised. MongoDB gives you two families. Logical backups with mongodump export the documents as BSON files plus each collection's metadata (options and index definitions), and mongorestore loads them back, rebuilding the indexes. Physical backups copy the data files themselves: a filesystem or cloud-volume snapshot, or the managed backups in Atlas and Ops Manager. From my notes: "Backup & restore: mongodump and mongorestore". That's the right starting point, and the one interviewers expect you to know by name.
The mental model: mongodump is photocopying every page of a book; a snapshot is photographing the whole shelf at once. Photocopying is portable and selective (one database, one collection, even a query), but slow for a big library, and the pages you copy first may change before you finish. The snapshot is fast and consistent, but all-or-nothing and tied to the same storage format.
This ran on the three-member rs22 replica set from the previous chapter, against the ch22 database (customers, products, orders, plus an index on orders.customerId): dump the database, have someone drop a collection by mistake, and restore just that collection.
mongodump --db=ch22 --out=/backup/2026-10-16
cat /backup/2026-10-16/ch22/orders.metadata.json
mongosh --quiet ch22 --eval 'db.orders.drop()' # the accident
mongorestore --nsInclude="ch22.orders" /backup/2026-10-16
mongosh --quiet ch22 --eval 'db.orders.countDocuments()'
mongosh --quiet ch22 --eval 'db.orders.getIndexes().map(i => i.name)'2026-10-16T16:16:37.701+0000 writing `ch22.products` to `/backup/2026-10-16/ch22/products.bson`
2026-10-16T16:16:37.702+0000 writing `ch22.customers` to `/backup/2026-10-16/ch22/customers.bson`
2026-10-16T16:16:37.702+0000 writing `ch22.orders` to `/backup/2026-10-16/ch22/orders.bson`
2026-10-16T16:16:37.702+0000 done dumping `ch22.orders` (3 documents)
2026-10-16T16:16:37.702+0000 done dumping `ch22.customers` (6 documents)
2026-10-16T16:16:37.702+0000 done dumping `ch22.products` (8 documents)
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"},{"v":{"$numberInt":"2"},"key":{"customerId":{"$numberInt":"1"}},"name":"customerId_1"}],"uuid":"eadf70171b7948f880cebe3c4278b7a0","collectionName":"orders","type":"collection"}
true
2026-10-16T16:16:37.893+0000 preparing collections to restore from
2026-10-16T16:16:37.893+0000 don't know what to do with file `/backup/2026-10-16/ch22/prelude.json`, skipping...
2026-10-16T16:16:37.893+0000 reading metadata for `ch22.orders` from `/backup/2026-10-16/ch22/orders.metadata.json`
2026-10-16T16:16:37.903+0000 restoring `ch22.orders` from `/backup/2026-10-16/ch22/orders.bson`
2026-10-16T16:16:37.913+0000 finished restoring `ch22.orders` (3 documents, 0 failures)
2026-10-16T16:16:37.913+0000 restoring indexes for collection `ch22.orders` from metadata
2026-10-16T16:16:37.913+0000 index: &idx.IndexDocument{Options:bson.M{"name":"customerId_1", "v":2}, Key:bson.D{bson.E{Key:"customerId", Value:1}}, PartialFilterExpression:(*bson.D)(nil)}
2026-10-16T16:16:37.949+0000 3 document(s) restored successfully. 0 document(s) failed to restore.
3
[ '_id_', 'customerId_1' ]mongodump --db=ch22connects like any client (tolocalhost:27017by default), reads every collection inch22and writes one.bsonfile of documents plus one.metadata.jsonper collection into/backup/2026-10-16/ch22/. It dumps up to 4 collections in parallel, which is why the log lines interleave.orders.metadata.jsonholds the collection's options and the index definitions,_id_andcustomerId_1, not the index data: indexes are rebuilt on restore. Aprelude.jsonnext to it records the server and tools versions ({"ServerVersion":"9.0.4","ToolVersion":"100.19.1"}).db.orders.drop()is the accident (true): the collection and its indexes are gone.mongorestore --nsInclude="ch22.orders"picks one namespace out of the dump directory. It recreates the collection, inserts the 3 documents, then buildscustomerId_1from the metadata. The "don't know what to do with prelude.json" line is harmless.- Afterwards the collection is back with both indexes. The dump is portable: the same directory could be restored into another server, another database name or Atlas, as long as it runs the same major version or feature compatibility version.
mongorestore only inserts. Restoring into a collection that still has the documents fails per document and carries on:
mongorestore --nsInclude="ch22.orders" /backup/2026-10-16 # orders still exist
mongorestore --nsInclude="ch22.orders" --drop /backup/2026-10-16 # drop first, then restore
mongorestore --nsFrom="ch22.*" --nsTo="ch22_restore.*" /backup/2026-10-162026-10-16T15:54:31.940+0000 continuing through error: E11000 duplicate key error collection: ch22.orders index: _id_ dup key: { _id: 1 }
2026-10-16T15:54:31.940+0000 continuing through error: E11000 duplicate key error collection: ch22.orders index: _id_ dup key: { _id: 2 }
...
2026-10-16T15:54:24.139+0000 0 document(s) restored successfully. 3 document(s) failed to restore.
2026-10-16T15:54:24.227+0000 3 document(s) restored successfully. 0 document(s) failed to restore.
2026-10-16T15:54:24.326+0000 17 document(s) restored successfully. 0 document(s) failed to restore.- The first restore hits
E11000for every document, because each_idalready exists. It never overwrites:0 document(s) restored successfully. 3 document(s) failed. --dropdrops each target collection before restoring it, so the result is exactly the dump. That's what you want for "put it back as it was", and it's also how a careless restore wipes newer data.--nsFrom/--nsTorename namespaces on the way in: all 17 documents land in a newch22_restoredatabase, the safe way to inspect a backup next to live data before copying anything back.
A plain dump copies collections one after another, so if writes continue, collections are copied at different moments. On a replica set member, --oplog also captures the oplog entries written during the dump, and --oplogReplay replays them on restore, so the result is one consistent moment: the end of the dump. Here a script keeps inserting orders every 10 ms during a full dump of a 400,000-document database:
mongodump --oplog --out=/backup/full
mongorestore --host=solo:27017 --oplogReplay /backup/full # into a fresh, empty mongod
mongosh --host=solo:27017 --quiet ch22 --eval 'db.orders.countDocuments()'2026-10-16T15:55:25.251+0000 writing `ch22.big` to `/backup/full/ch22/big.bson`
2026-10-16T15:55:25.251+0000 writing `ch22.orders` to `/backup/full/ch22/orders.bson`
...
2026-10-16T15:55:25.252+0000 done dumping `ch22.orders` (123 documents)
2026-10-16T15:55:25.454+0000 done dumping `ch22.big` (400000 documents)
2026-10-16T15:55:25.454+0000 writing captured oplog to ``
2026-10-16T15:55:25.454+0000 dumped 15 oplog entries
...
2026-10-16T15:55:47.289+0000 finished restoring `ch22.orders` (123 documents, 0 failures)
2026-10-16T15:55:48.636+0000 replaying oplog
2026-10-16T15:55:48.637+0000 applied 15 oplog entries
2026-10-16T15:55:48.650+0000 400137 document(s) restored successfully. 0 document(s) failed to restore.
137orderswas copied early, when it held 123 documents. The big collection took another 200 ms, during which the writer kept inserting.- Meanwhile
--oplogrecorded every oplog entry from the start of the dump to its end: 15 entries, saved asoplog.bsonat the top of the dump directory. - The restore loads the 123 copied orders, then replays the 15 entries. The oplog is idempotent (previous chapter), so an entry for a document the copy already contained does no harm.
- The restored
ordershas 137 documents: the state at the moment the dump finished, not a mix of moments. 400,137 documents in total: 400,000 inbig, 137 orders and the other two collections. - Limits:
--oplogneeds a full dump (with--dbit fails:Failed: bad option: --oplog mode only supported on full dumps), it doesn't work throughmongos, and it fails if someone renames a collection or changes users during the dump.
--archive writes the whole dump as one file (or to stdout, to pipe somewhere) and --gzip compresses it:
mongodump --db=ch22 --archive=/backup/ch22.archive.gz --gzip
ls -l /backup/ch22.archive.gz2026-10-16T15:54:24.342+0000 done dumping `ch22.customers` (6 documents)
-rw-r--r-- 1 root root 1070 Oct 16 15:54 /backup/ch22.archive.gzRestoring it (here into a new database name) reads the same single file:
mongorestore --archive=/backup/ch22.archive.gz --gzip --nsFrom="ch22.*" --nsTo="ch22_archive.*"2026-10-16T16:15:53.065+0000 17 document(s) restored successfully. 0 document(s) failed to restore.Things to know:
mongoexport/mongoimportare not backups. They write JSON or CSV, which can lose BSON types (dates,Decimal128,ObjectIdneed Extended JSON) and carry no index definitions. Use them for data exchange.- Sharded clusters:
mongodumpthroughmongoscan't use--oplog, so writes during the dump make it inconsistent across shards. Use coordinated snapshots, Atlas or Ops Manager, or follow the documented procedure of stopping the balancer and dumping each shard. - Encrypted collections: the docs say
mongodumpisn't supported for Queryable Encryption or CSFLE collections, and it doesn't decrypt anything. Here it did dump them, as ciphertext (see Field-level and Queryable Encryption); export decrypted data with a driver instead. - Time: the dump itself is fast, but a restore rebuilds every index. On a large database that can take hours, which is why big systems restore from snapshots.
- Run
mongodumpagainst a secondary (--readPreference=secondary) to keep the load off the primary. The default is the primary.