Search code examples
databasemongodbenvironment-variablesinitializationmongock

Best way to init database with specific data by environment (dev, pprod, prod) using Mongock


I'm using Mongock to init a MongoDb database with some configs, An array of authorized users by calling system. {systemId: 'a', authorizedUsers: ['user1', user2]}.

My problem come from the fact that in dev user1 and user2 are authorized but in prod only user1 is authorized.

  • is it better to add an env property {env: 'dev', systemId: 'a', authorizedUsers: ['user1', user2]} and use it as a filter when we search for authorized users ? The downside is to have different configs available in DB and we need to choose the right one.
  • Or is it better to read in Mongock init function (the ChangeSet) the env where Mongock is running on and init the right data ? The downside is that we can't test the correctness of the init before to be in the right environnement
  • A better solution ?

Thank you in advance for your responses

Edit to clarify the two options

  • Option 1

    @ChangeLog
    public class UsersChangeLogs {
    
     @ChangeSet(...)
     public void addUsers() {
     //add dev users {env: 'dev', systemId: 'a', authorizedUsers: ['user1', 'user2']}
     //add prod users {env: 'prod', systemId: 'a', authorizedUsers: ['user1', 'user2']}
     }
    
    }

with


    @Service
    class AuthorizedUsers {
     @Value("env")
     private String env;
     List<User> getAuthorizedUsers() {
      return db.users.filter(env)
    }
    }

  • Option 2: (proposed by @Mongock team)(choosed)

    @ChangeLog
    public class UsersChangeLogs {
    
     @Profile("dev")
     @ChangeSet(...)
     public void addUsers() {
     //add dev users {systemId: 'a', authorizedUsers: ['user1', 'user2']}
     }
    
     @Profile("prod")
     @ChangeSet(...)
     public void addUsers() {
     //add prod users {systemId: 'a', authorizedUsers: ['user1', 'user2']}
     }
    
    }


Solution

  • If I am not wrong, I see two parts in this problem

    1. Where to store the user's configuration/how to pass it to Mongock
    2. Based on that configuration, initialise your MongoDB database.

    I guess we both agree the second step is clear: Mongock somehow takes the configuration and performs the migration.

    Regarding of how to provide that configuration to Mongock, in your first option you mention to add a field for the environment, right? Are you saying you have the same database for production and dev environments? In my opinion, unless you have a really good reason for it, I wouldn't recommend that. In my ideal world, you would have a database per environment, so that field for environment is not needed. Mongock just needs to take the information from that collection that has been previously added.

    Then the issue is how that configuration data about users is added to the database. If it can be hardcoded from your java code you can easily do it in Mongock. If you are using Spring you can use @Profile to talle which changeLog execute in which environment.

    If not, another idea is passing those users as environment variables or configuration. If you are using kubernetes, ansible of that kind of tool, providing it by environment variable is not a bad idea. But I guess I don't have enough information to get more committed with any option.

    @Profile("dev")
    @ChangeLog
    public class DevUsersChangeLogs {
    
     @ChangeSet(...)
     public void addUsers() {
     //add users {systemId: 'a', authorizedUsers: ['user1', 'user2']}
     }
    
    }
    
    @Profile("prod")
    @ChangeLog
    public class ProdUsersChangeLogs {
    
     @ChangeSet(...)
     public void addUsers() {
     //add users {systemId: 'a', authorizedUsers: ['user1']}
     }
    
    }
    

    And then you can perform your migration based on your users

    @ChangeLog
    public class ProperMigration {
    
     @ChangeSet(...)
     public void changeSetMethod() {
     //migration code
     }
    
    
    }