A lot has already been said about all the advantages of schema-less databases. They make a bunch of cumbersome tasks simpler and sometimes, much faster. But any relevant system cannot be totally “schema-less”; they expect at least some core structure to work with.

But is it really necessary to “validate” your schema from both your application and database? Sometimes, it sounds like overkill to me as most of the side effects of schema-less databases can be easily handled in the application code itself or in the query language (N1QL in our case). Of course, as your model evolves, it might get a little bit trickier to handle every single possibility since the project start.

In those cases, we commonly run data migrations (aka: execute Updates, Inserts or deletes) to migrate the “old schema” to the new one. Ideally, those migrations need to be executed automatically, sequentially, and if something goes wrong, the whole application start should fail.

Well, turns out that it is exactly what liquicouch does! It is a liquibase-like Java implementation for Couchbase. Let’s see how it works:

 

Getting started

With Maven

with Gradle

 

Usage with Spring

You need to instantiate the Liquicouch object and provide some configuration. If you use Spring, it can be instantiated as a singleton bean in the Spring context. In this case, the migration process will be executed automatically upon startup.

 

Usage without Spring

Using LiquiCouch without a spring context has a similar configuration but you have to remember to run execute() method to start the migration process.

The examples above provide minimal configuration. However, the Liquicouch object provides some other possibilities (setters) to make the tool more flexible:

 

Creating Change Logs

ChangeLog contains a bunch of ChangeSets. ChangeSet is a single task (set of instructions made on a database). In other words, ChangeLog is a class annotated with @ChangeLog and contains methods annotated with @ChangeSet.

 

@ChangeLog

A class with change sets must be annotated by @ChangeLog. There can be more than one change log class but in that case, an order argument must be provided:

ChangeLogs are sorted alphabetically (that is why it is a good practice to start the order with zeros) by order argument, and change sets are applied due to this order.

 

@ChangeSet

A method annotated by @ChangeSet is taken and applied to the database. The history of applied change sets is stored in a dbChangeLog type document.

 

Annotation parameters:

  • order – a string for sorting change sets in one changelog. It sorts alphabetically in an ascending order. It can be a number, a date etc.
  • id – a name of a change set that must be unique for all change logs in a database
  • author – the author of a changeSet
  • runAlways – [optional, default: false] changeset will always be executed but only the first execution event will be stored as a document.
  • recounts – [optional, default: 0] [Only applied when changSet returns a ParameterizedN1qlQuery] if you want to be sure that all documents have been updated, you can return a ParameterizedN1qlQuery. This query expects a result called size. If size is not zero, the query will be executed again according to the number of recounts specified. If none of the recounts returns zero, an exception will be thrown, and the application will fail to start.
  • retries – [optional, default: 0] [Only applied when changSet returns a ParameterizedN1qlQuery] if the recount operation fails (the count result isn’t zero), it will rerun the changeSet in an attempt to update the remaining documents (Your changeSet should be able to run multiple times without any side effects). If all retries fail, an exception will the thrown and the application will fail to start.

 

Defining ChangeSet methods

Methods annotated by @ChangeSet can have one of the following definition:

Without Spring

 

 

Demo Project

You can clone the sample project here https://github.com/deniswsrosa/liquicouch-demo

 

Documentation

https://github.com/deniswsrosa/liquicouch

Support

This is a community project mainly supported by me. If you have any issues or questions, just ping me at @deniswsrosa

Posted by Denis Rosa, Developer Advocate, Couchbase

Denis Rosa is a Developer Advocate for Couchbase and lives in Munich - Germany. He has a solid experience as a software engineer and speaks fluently Java, Python, Scala and Javascript. Denis likes to write about search, Big Data, AI, Microservices and everything else that would help developers to make a beautiful, faster, stable and scalable app.

Leave a reply