Is it possible to use MongoDb and PostgreSql for same model in Spring boot?

Tags: , , ,



I have built a User management service in which I’m using MongoDb (spring data). I have two models User and Role.

package com.userservice.usermanagement.models;

import java.util.HashSet;
import java.util.Set;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "user_data")

public class User {
    /**
     * User model
     */
    
      @Id
      private String id;

      
      private String username;

     
      private String email;

      
      private String password;
      
      private String customername;
      
      private String customerid;
      
      private String description;
      

      public String getCustomerid() {
        return customerid;
    }

    public void setCustomerid(String customerid) {
        this.customerid = customerid;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getCustomername() {
        return customername;
    }

    public void setCustomername(String customername) {
        this.customername = customername;
    }

    @DBRef
      private Set<Role> roles = new HashSet<>();

      public User() {
      }

      public User(String username, String email, String customername,String customerid,String description, String password) {
        this.username = username;
        this.email = email;
        this.customername = customername;
        this.customerid = customerid;
        this.description = description;
        this.password = password;
      }

      public String getId() {
        return id;
      }

      public void setId(String id) {
        this.id = id;
      }

      public String getUsername() {
        return username;
      }

      public void setUsername(String username) {
        this.username = username;
      }

      public String getEmail() {
        return email;
      }

      public void setEmail(String email) {
        this.email = email;
      }

      public String getPassword() {
        return password;
      }

      public void setPassword(String password) {
        this.password = password;
      }

      public Set<Role> getRoles() {
        return roles;
      }

      public void setRoles(Set<Role> roles) {
        this.roles = roles;
      }
    }

Role model –

package com.userservice.usermanagement.models;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "roles")
public class Role {
    /**
     * Model for role with all the attributes
     */
      @Id
      private String id;

      private URole name;

      public Role() {

      }

      public Role(URole name) {
        this.name = name;
      }

      public String getId() {
        return id;
      }

      public void setId(String id) {
        this.id = id;
      }

      public URole getName() {
        return name;
      }

      public void setName(URole name) {
        this.name = name;
      }
    }

and Role enumerator-

package com.userservice.usermanagement.models;

public enum URole {
    ROLE_USER,  
    ROLE_ADMIN
}

In User there is a role attribute which I have @Dbref to role collection. My problem is that I want to have a option of using PostgreSql and MongoDb in the same application for these Models. I have implemented this for MongoDb but I’m not sure how to go about doing this for postgreSql in the same application as an option. One way I think is to have a interface User and role and build two different classes for User_mongo model and User_postgre entity(same way for role). I’m stuck here, and I tried to do certain research but most of the time I find tutorials that have separate databases of same type(Both PostgreSql databases). Any direction is highly appreciated. PS I’m new to spring boot and Java.

My AddUser Controller that Uses Mongorepository as of now

@PostMapping("/adduser")
//  @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) {
        /*
         * This controller Creates new user based on all the entities for the user
         * 
         */
        if (userRepository.existsByUsername(signUpRequest.getUsername())) {
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Username is already taken!"));
        }

        if (userRepository.existsByEmail(signUpRequest.getEmail())) {
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Email is already in use!"));
        }

        // Create new user's account
        User user = new User(signUpRequest.getUsername(), 
                             signUpRequest.getEmail(),
                             signUpRequest.getCustomername(),
                             signUpRequest.getCustomerid(),
                             signUpRequest.getDescription(),
                             encoder.encode(signUpRequest.getPassword()));
        

        Set<String> strRoles = signUpRequest.getRoles();
        Set<Role> roles = new HashSet<>();
      
        if (strRoles == null) {
            Role userRole = roleRepository.findByName(URole.ROLE_USER)
                    .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
            roles.add(userRole);
        } else {
            strRoles.forEach(role -> {
                switch (role) {
                case "admin":
                    Role adminRole = roleRepository.findByName(URole.ROLE_ADMIN)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(adminRole);

                    break;
                
                default:
                    Role userRole = roleRepository.findByName(URole.ROLE_USER)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(userRole);
                }
            });
        }

        user.setRoles(roles);
        userRepository.save(user);

        return ResponseEntity.ok(new MessageResponse("User Added successfully!"));
    }
    ```

Answer

I would use the @ConditonalOnProperty annotation here on two configs(one for Mongo and one for PostgerSql), and add the enabled config-property at runtime(For the config you want it’s beens to load)

Here is a simplified example.

 public static void main(String[] args) {
        SpringApplication application = new SpringApplication(DemoApplication.class);
        Properties properties = new Properties();
        properties.put("databaseFoo.enabled", "true");
        application.setDefaultProperties(properties);
        application.run(args);
    }
    then on the config needed when run time is databaseFoo you can annotate the bean as such
    
        @ConditionalOnProperty(
            value="databaseFoo.enabled",
            havingValue = "true")
    public class DatabaseFooConfig {
    Then the other bean could have the following conditional properties
    
            @ConditionalOnProperty(
            value="databaseBar.nabled",
            havingValue = "false",
            matchIfMissing= true)
    public class DataBaseBarConfig {


Source: stackoverflow