How to dump & restore a MongoDB database from a docker container

How to dump & restore a MongoDB database from a docker container

MongoDB is an interesting tool. Dead simple to create and modify records (or, "documents") that are basically pure JSON goodness, juxtaposed with tools or commands that at times make you scratch your head in utter confusion and/or disbelief.

πŸ“£
2023/03/14 Update: I have updated the guide below to include mentions of using the --uri flag when using a connection URL, another, more streamlined method that lets you directly pipe the database dump in and out of containers, and I have also included updates for MongoDB's newer requirement to use --nsInclude with the restore command instead of the now considered to be deprecated --db flag.

The original method that relies on multiple (one per collection) json files that have to be copied in-and-out of containers is preserved too, as there are practical use-cases for that option.

To keep me from having to re-figure this out a few more times, here's a quick how-to on how to back up and restore a MongoDB database, all collections included. The process is unfortunately a little less elegant as compared to PostgreSQL or MariaDB, but hopefully you don't have to do it too often.

How to dump & restore a PostgreSQL database from a docker container
Sometimes you need to quickly dump and restore a PostgreSQL database, but what’s the easiest way to do this when your database is in a Docker container? How to dump & restore a MariaDB/MySQL database from a docker containerIn the same vein as my previous post on dumping and
How to dump & restore a MariaDB/MySQL database from a docker container
In the same vein as my previous post on dumping and restoring your PostgreSQL database, here are mostly copy/paste-able commands for when you’re using a MariaDB or MySQL database. How to dump & restore a PostgreSQL database from a docker containerSometimes you need to quickly dump and restore a

Create a database dump

We can use the following command to create a dump of your entire database, all collections included. This assumes your source database is (also) in a container, but the command would be roughly identical if you your source database is directly installed on your (virtual) machine too.

Method one: Mongodump's default individual collection dump files

By default a mongodump export generates individual files, one for reach collection. If this is the method you'd like to use, we won't be able to rely on shell piping to get the files directly out of our database container. For this we can use an intermediary step of storing the dumped database files in a directory within the container, which we can then copy out to our host using docker cp – or if you already have a host directory mounted as a volume, you can use that and skip the docker cp step altogether of course.

Here's an example that dumps your entire database to the /dump directory within your container:

❯ docker exec -i <container_name> /usr/bin/mongodump --username <username> --password <password> --authenticationDatabase admin --db <database_name> --out /dump

Or if you use a mongodb+srv or similar URL to connect to your database instead:

❯ docker exec -i <container_name> /usr/bin/mongodump --uri "<your mongodb+srv link>" --out /dump

Now that we have the resulting files we can copy them out of the container and to our host. Here I am using the ~/Downloads destination as an example:

❯ docker cp <container_name>:/dump ~/Downloads/dump

Method two: Pipe results directly out of the container into a single dump

There is a flag we can use that changes the behavior of mongodump to instead send everything out into a single archive file or stdout, which we can use to directly pipe everything we need out of the container into a file on our host machine – or indeed to machine we are running these container commands from. This is what what would look like:

❯ docker exec -i <container_name> /usr/bin/mongodump --username <username> --password <password> --authenticationDatabase admin --db <database_name> --archive > ~/Downloads/mongodb.dump

Or again, if you are using a connection URL:

❯ docker exec -i <container_name> /usr/bin/mongodump --uri "<your mongodb+srv link>" --archive > ~/Downloads/mongodb.dump
πŸ’‘
Keep in mind that in these examples, the ~/Downloads/mongodb.dump file will be created on the host machine, or at least on whatever machine you are running these commands from, not within the container.

That's it, we finally have our files. Now we can basically do the exact opposite in our new container. Let's do that next.


Restoring

Now that we have the database dump files ready, let's go ahead and import (or, restore) them. Whether this is a fresh and new container or you're restoring a backup, the process is the same.

Ensure a user is created first

Before we continue, we should make sure we have a database user account ready with read and write access to the database you want to restore into. If you don't have one already, let's go ahead and create one now.

You can run the following in your mongodb (cli) client of choice to create a new user. A prompt will appear after running this command in which you can specify the user's password.

use admin

db.createUser({
    user: "username",
	pwd: passwordPrompt(),
	roles:[{role: "readWrite" , db:"<database_name>"}]})

Why "use admin"

One part that seems somewhat confusing and that threw me off previously is that by default when you try to connect to a MongoDB server it expects that admin is the database in which the user exists – even if said user has no access permissions for this database.

There are ways to change this behavior, but that is outside the scope of this guide. As you specify user roles that specify which database(s) the user has actual access to, even though the user might exist in the admin database, it doesn't actually have any permissions to do anything there, so it seems to not be that big of a deal.

Slightly confusing, but that seems to be the Mongo way. Anyway, let's continue.

Method one: Mongodump's default individual collection dump files

If you used the first method and have multiple individual files that make up your database dump, then we should first make the dumped database files available within the docker container by copying them into the container:

❯ docker cp ~/Downloads/dump <container_name>:/dump

Restore

Now that the dump files are available within the container, run the following command to have everything be imported.

❯ docker exec -i <container_name> /usr/bin/mongorestore --username <username> --password <password> --authenticationDatabase admin --nsInclude=<database_name>.\* /dump/<database_name>

Or if you use a URL to connect to your destination database:

❯ docker exec -i <container_name> /usr/bin/mongorestore --uri "<your mongodb+srv link>" /dump/<database_name>
πŸ’‘
When mongodump creates a databasae dump, by default all files are placed in a sub-directory named after the database. That's why in the above example the path points to /dump/<database_name>. You can leave this part off if you have a different folder structure.

Cleaning up afterwards

If you'd like to delete the dump files from the container after importing, you can open a shell session within the docker container like so:

❯ docker exec -it <container_name> /bin/bash

Now you can delete these files by running something like rm -rf /dump.

Method two: Pipe results directly into the container

If you used the second method as described above, then we can use the same approach to import the dump by directly piping it into the container, like so:

❯ docker exec -i <container_name> /usr/bin/mongorestore --username <username> --password <password> --authenticationDatabase admin --nsInclude="<database_name>.*" --archive < ~/Downloads/mongodb.dump

Or if you're using a URL to connect to your destination database:

❯ docker exec -i <container_name> /usr/bin/mongorestore --uri "<your mongodb+srv link>" --archive < ~/Downloads/mongodb.dump
πŸ’‘
My guide originally used the --db <database_name> flag in the above restore commands too, but these have since been marked as deprecated and --nsInclude has be used instead, with the name of your database along with names of collections you wish to import, or a wildcard for all collections.

The entire value must be wrapped in quotation marks, or at least the wildcard must be escaped (\*), to ensure it is passed through to the command, and not read by bash as an actual wildcard.

That's it! While not as straight-forward as with some other database solutions, it's not too difficult fortunately.

I hope this guide was able to help you. I certainly will be re-visiting this myself once I inevitably end up forgetting how to do this stuff.

Thank you.