Advanced Schema Patterns and Antipatterns / Apply Advanced Schema Design Patterns
Database schemas change. It's not a question of if, but when it will happen. Dealing with schema changes can be stressful. But MongoDB makes it easier with the schema versioning pattern.
By adding an extra field in our documents and using some application support, we can change schemas with no downtime. MongoDB makes this possible thanks to its flexible document model. Documents with different shapes or schema versions can exist within the same collection. Since these documents can coexist, we have flexibility on how and when we implement schema updates, which helps avoid downtime.
Let's look at an example of modifying a schema used by our bookstore app. Here we have a user and the user's collection with their home and work phone numbers listed in this document. Later, we added another user who doesn't have a home phone but who does have other contact methods, including work phone, Skype and WhatsApp. Instead of adding several additional fields to manage the growing list of contact methods, let's use an array.
This array holds a list of sub documents. Each sub document references the contact type and value. To help our app identify the new shape, we've added a schema version field and set it to two. The absence of a schema version field is an implicit version 1.
This ability to have multiple schemas coexist in MongoDB is in contrast to a relational database where you can only have one schema version per database, or one per table. With MongoDB, you can change the schema and increment the schema version number. Every document in a MongoDB collection can have a unique schema version number and therefore a unique shape. In practice, we rarely have more than a couple of versions while the app is in transition.
How do we update existing documents to the new shape? We can either have the application update the shape when the document is accessed or have a background task performed updates on all documents. Keep in mind that before we update the schema, we must first update the application so it can read all schema versions, old and new, of the documents involved. OK, now let's use a background task to update all documents to the new schema without any downtime.
Assume we've already updated the application to handle both old and new schemas. We start by updating our application servers. Then we update the documents by running the background task, which can take as much time as needed. While the documents are updating, the app servers can handle both schema versions.
We can also run the background task with multiple passes to take advantage of when the system is less busy. After all documents are updated, we can remove the code to handle old versions from our app. To summarize, the schema versioning pattern allows you to perform a schema update without application downtime. To implement the schema versioning pattern, add a field in each document to track the version number.
You also need to update the app to handle different document shapes. And develop a strategy to migrate documents to the new schema. Remember all applications will require schema changes. The schema versioning pattern allows you to avoid application downtime, puts you in control of migrations, and lets you choose when you want to do them.
