May 23, 2023

Get Started: Liquibase MongoDB Pro Extension (with examples)

Since our Liquibase team released the MongoDB Pro Extension, I've been excited to try it out. By combining the power of the MongoDB Pro Extension with Liquibase, you can streamline your database development workflow, ensuring efficient and controlled management of MongoDB databases. This integration provides a seamless experience for handling changes, allowing teams to easily adapt and evolve their MongoDB databases while maintaining data integrity and application stability. 

In this blog post, I'll walk you through the proper setup of the Liquibase MongoDB extension to bring better automation and governance to your databases.

Liquibase MongoDB webinar banner

We also hosted a webinar in April, -"Automate MongoDB: Build Successful CI/CD in the Cloud," in which we give a full demo. If you prefer to watch, head to that link for the on-demand recording.

Note that you�ll need a Pro license for Liquibase because the MongoDB Pro extension is only accessible from Liquibase Pro. You might have guessed that from the �Pro� in the name! If you aren�t already a Pro user, you can get a 30-day trial license without any credit card and no obligation. Just sign up for a Pro Trial on the website.

MongoDB setup

First, I need a MongoDB environment. I installed the MongoDB Community Edition onto my Mac (you can find instructions for all different environments on Mongo's page for installing Community Edition).

It's amazingly straightforward. On a Mac, most people use Homebrew like I do. All I did was tap the MongoDB repository, run an update, then install MongoDB Community Edition 6.0 and start it up as a service.

Here are the commands I ran from a terminal window:

> brew tap mongodb/brew> brew update> brew install mongodb-community@6.0> brew services start mongodb-community@6.0

Now that MongoDB is running, I connected using the mongosh command just to verify that everything worked. It took me into the mongodb-shell and the test database. I'll run show collections to see if any collections exist.

> mongoshtest> show collectionstest>

No collections exist yet in the test database. I am connected and everything seems to be working. When the mongodb-shell starts up, I get the warning:

Access control is not enabled for the database. Read and write access to data and configuration is unrestricted

That's okay for my purposes because I am just running locally and testing these features. I would never leave it that way for a MongoDB I use for real purposes. Now that we have our MongoDB environment, we can go to our Liquibase setup.

Setting up Liquibase for MongoDB

Setting up Liquibase is easy, too. I found the instructions to install Liquibase and chose the Homebrew method. Here's what that looks like:

> brew install liquibase> export LIQUIBASE_HOME=$(brew --prefix)/opt/liquibase/libexec

Now when I run liquibase --version, I should see the newly installed version of Liquibase. Something like:

Liquibase Version: 4.21.1

I now have MongoDB and Liquibase installed. Next, I need a couple more pieces to test out the MongoDB Pro Extension.

Setting up and testing the Liquibase MongoDB Pro extension

First, I created a directory to work from, liquibase-mongodbpro, and everything I did is in that directory.

> mkdir liquibase-mongodbpro> cd liquibase-mongodbpro

To store the Pro key, I'll create a liquibase.properties file. Other Liquibase properties will be added later.

> touch liquibase.properties

Open the file liquibase.properties with your favorite editor to add your pro license key. The property name is liquibase.licenseKey as shown here:

liquibase.licenseKey: 

In my case, I copied the key from my email and used the pbpaste command to add it to the file from my terminal.

> echo liquibase.licenseKey: $(pbpaste) >> liquibase.properties

Now when I run liquibase --version it shows me that I have Liquibase Pro with a warning about my license expiring in 30 days.

The next thing I did was grab the MongoDB Pro extension. The full documentation for the MongoDB Pro Extension includes all the details, but I'll include a few simple steps here.

First, I downloaded the jar with the MongoDB Pro extension. It's in the Maven repository and at the time of this writing 1.0.0 is the latest version. You can download it by just clicking on it, but I use curl to pull it down to my local directory.

> curl --output liquibase-commercial-mongodb-1.0.0.jar https://repo1.maven.org/maven2/org/liquibase/ext/liquibase-commercial-mongodb/1.0.0/liquibase-commercial-mongodb-1.0.0.jar

I moved that jar into the lib directory for Liquibase so that it can use the extension. The lib directory is in the Liquibase HOME directory that we set up earlier.

> cp liquibase-commercial-mongodb-1.0.0.jar $LIQUIBASE_HOME/lib/

Now I can safely add the URL that Liquibase should use when it connects to our MongoDB instance. I add another property to our liquibase.properties called url.

> echo url: mongodb://localhost:27017/test >> liquibase.properties

Note the mongodb portion of the URL. That's what tells Liquibase which extension to use.

Creating the First Changelog

The final piece I needed was a changelog. The file tells Liquibase what I want to do. For this test scenario, I just wanted to insert some elements into the database. I created a simple JS file that has standard Mongo syntax in it. After all, that's one of the features of the Pro version I wanted to test out.

Building off Jenn's example from the webinar, I wanted to insert four students. I created a file called insert-students.js and it looks like this:

db.students.insertMany(
    [
        { name: "Alice Wonderland", year: 2018, major: "History", address: { city: "NYC", street: "123 33rd St.", state:"New York"}},
        { name: "White Rabbit", year: 2017, major: "English", address: { city: "Rabbit Hole", street: "999 Main Street", state:"New York"}},
        { name: "Mad Hatter", year: 2024, major: "Math", address: { city: "Hattery", street: "5th Ave.", state:"New York"}},
        { name: "Dutches", year: 2034, major: "English", address: { city: "The Manor", street: "123 Sycamore St.", state:"New York"}}
    ]
)

Now I wanted to tie that into Liquibase so that it knows how to manage it. I referenced insert-students.jsin a Liquibase changelog. Since we are already using JSON, I wanted to use JSON for my changelog, too. You could use other formats like XML, for example. The changelog file named dbchangelog.json looks like this:

{
    "databaseChangeLog": 
    [
        {
            "changeSet": {
                "id": "create_students-collection",
                "author": "pj",
                "runWith": "mongosh",
                "changes": [
                  {
                    "mongoFile": {
                      "dbms": "mongodb",
                      "path": "insert-students.js",
                      "relativeToChangelogFile": true
                    }
                  }
                  ],       
                "rollback": [
                    {
                      "mongo": {
                        "mongo": "db.students.drop()"
                      }
                    }
                ]
            }    
        }
    ]
}

Notice that I refer to the insert-student.js file. Also, notice that I am cheating a bit by setting the rollback to simply drop the entire students collection. That's not the right long-term solution, but for now, it will facilitate my testing.

To check if I have everything in the right location, I ran the liquibase status command to see if it detected that a change needs to be made.

> liquibase status --changelog-file dbchangelog.json

If everything is configured correctly, Liquibase should detect that one changeset has not been applied. I'll see that in the output from the status command like:

1 changesets have not been applied to @localhost:27017

Now I was ready to run Liquibase and update my MongoDB.

> liquibase update --changelog-file dbchangelog.json

Output from this command, you will see the UPDATE SUMMARY information, like:

UPDATE SUMMARY
Run:                          1
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            1

When I ran update again, it tells me that my update was previously run. So after the second run, the UPDATE SUMMARY looks like:

UPDATE SUMMARY
Run:                          0
Previously run:               1
Filtered out:                 0
-------------------------------
Total change sets:            1

I also confirmed my results by going back to my mongosh terminal and interrogating the MongoDB database directly. For example, I showed all collections to see what Liquibase added:

test> show collections
DATABASECHANGELOG
DATABASECHANGELOGLOCK
students

I saw the students collection. And I also saw the DATABASECHANGELOG and DATABASECHANGELOGLOCK that Liquibase uses for managing databases. Then I checked the students collection to see if it has the four students from our insert-student.js file.

test> db.students.find()
[
  {
    _id: ObjectId("6467dd078d515ef6399a0268"),
    name: 'Alice Wonderland',
    year: 2018,
    major: 'History',
    address: { city: 'NYC', street: '123 33rd St.', state: 'New York' }
  },
  {
    _id: ObjectId("6467dd078d515ef6399a0269"),
    name: 'White Rabbit',
    year: 2017,
    major: 'English',
    address: {
      city: 'Rabbit Hole',
      street: '999 Main Street',
      state: 'New York'
    }
  },
  {
    _id: ObjectId("6467dd078d515ef6399a026a"),
    name: 'Mad Hatter',
    year: 2024,
    major: 'Math',
    address: { city: 'Hattery', street: '5th Ave.', state: 'New York' }
  },
  {
    _id: ObjectId("6467dd078d515ef6399a026b"),
    name: 'Dutches',
    year: 2034,
    major: 'English',
    address: {
      city: 'The Manor',
      street: '123 Sycamore St.',
      state: 'New York'
    }
  }
]

Voila! The students were all there. I then tested rolling back with Liquibase to make sure that worked. And here I want to try out a Liquibase Pro feature, called rollback-one-changeset which lets me specifically pick which changeset I want to roll back.

> liquibase rollback-one-changeset --changelog-file dbchangelog.json --changeset-author PJ --changeset-id create_students-collection --changeset-path dbchangelog.json --force

And I saw in the output that it worked:

Liquibase command 'rollback-one-changeset' was executed successfully.

I also checked MongoDB directly. We expected the entire collection to be dropped. I used the show collections command to check.

test> show collections
DATABASECHANGELOG
DATABASECHANGELOGLOCK
test> 

Yes, indeed, the students collection no longer exists. The rollback worked as expected. If I rerun the liquibase update command, it'll put it right back. 

Easier database changes and migrations in MongoDB with Liquibase

I really like that MongoDB users can now keep their Mongo scripts in a form that suits them better. I have barely scratched the surface. Like taking advantage of Liquibase Pro's quality checks. We even have the option to create custom regex-based quality checks. There's a repository of Custom Quality Checks that you can investigate for interesting examples.

The MongoDB Pro Extension for Liquibase offers an intuitive solution for managing database changes and migrations in MongoDB. With clear instructions for setting up MongoDB and Liquibase, the process is straightforward and accessible for different environments.

Need help getting started? Contact us today, and we'll get you in touch with an expert who can guide you every step of the way.

Paul Julius
Paul Julius
Share on: