Is there a better way to deal with relational and non-relational databases in the same project?

Asked

Viewed 67 times

1

I am refactoring a code, where I process some data and send it to a database. I have two versions. One where I use Mongodb and the other where I use Mysql. But I’d like to put the two versions together (there’s a lot of duplicate code) and I was wondering how I could do that. Below is a piece of code where I create an Update class that I inherit either from Bancodedadosmongodb or Bancodedadossql. My idea was to put this scheme in all classes that connect to the database.

Is there a better way to do this? What do you think ? Would it be better to make two separate versions? One pro Mongodb and one pro Mysql ?

class Update(BancoDeDadosMongoDB):
    def __init__():
        self.db = super().__init__()
            
    def check_update_date():
        #Checa se o banco de dados escolhido 
        if issuclass(Update,BancoDeDadosMongoDB):
            #Faz a busca na coleção atualização
            result = self.db.atualizacaofind(
                {'ultima_atualizacao':{'$regex': '\d\d/\d\d/\d\d\d\d'}},
                {'_id':0}
                )
            return result
        
        if issubclass(Update,BancoDeDadosSQL):
            #Preciso ajeitar essa busca para buscar pela data de atualização.
            #Primeiro preciso ver como ficará organizado a tabela no BD relacional
            
            empresa =self.session.query(Config).filter(Config.ultima_atualizacao.like('\d\d/\d\d/\d\d\d\d')):
            
            return result

2 answers

5

The idea is to create an interface, and in this interface you define the operations that will exist for two banks, such as update, create, getById and etc. You must use a Repository for each domain object, in other words, for each entity or table in the database.

From there, you create a class for each database and implement this interface, ie, will implement these functions you defined (update, create, getById). Something like this:

class Interface_UsuarioRepository:
    # assinaturas
    update()
    create()
    getById(Id)


class UsuarioMongoDBImpl(Interface_UsuarioRepository):
    def update(): 
        # implementação do método update para o banco MongoDB
        ...


class UsuarioMySQLImpl (Interface_UsuarioRepository): 
    def update(): 
       # implementação do método update para o banco MySQL
       ...

And after that, instead of directly using the implementation you will use the principle of depedance inversion to depend only on abstraction, which in this case is the Usuariorepository interface. Something to that effect:

class Usuario:
   _repository: Interface_UsuarioRepository
   # /* CONSTRUTOR DA CLASSE Usuario */
   def __init__(self, repository):
       self._repository = repository

    
    def updateUser(self):
        self._repository.update()
    

That way, when you want to change between one bank and the other it is only necessary to instantiate the class User with User to the Mysql or Usuariomongodbimpl for Mongodb. Example:

usuario = Usuario(UsuarioMySQLImpl());
# Essa função vai ser executada com o banco Mysql
usuario.updateUser();

usuario = Usuario(UsuarioMongoDBImpl());
# Essa função vai ser executada com o banco MongoDB
usuario.updateUser();

Take a look at this repository pattern (Repository Pattern) and looks for how to implement this in python. I mixed a little the syntax of Java with other languages, I hope you have at least given a way for you to solve your problem.

  • 1

    Hi - I would answer basically the same thing - I took the liberty of editing your pseudo-code to get "pseudo code in Python". (The biggest difference is that Python does not have native "interfaces" - the most common substitute is multiple inheritance even though in this example it is not even necessary)

  • 1

    What can be added is that in Python, being very quiet the introspection is easy to make the itnerfaces for SQL and Mongodb be "generic" and introduce the fields (and table name/Collection) in the parent class (and then to avoid a very magical layer the best is that the repository methods explicitly receive the parent object)

  • Its edition was super welcome, I lacked Skills in Python to build an example in it :D.

  • Thanks for the reply, @jsbueno !!! Helped yes , and a lot!

2

(Another in the hype of the Mongodb that no one needs in 99% of cases... should be just to practice the concept ).

What will be recorded in both cases are distinct structures, in the case of the relational in particular will be recorded something in a combination of tables that depends on the business rule, I mean, of each type of content to be recorded at each moment in the code. So I guess you can’t extract a general case that fits all the situations in the code, if you try it, it won’t be legal. For searches will be the same thing, the search criteria I believe will make a difference to each other.

Let me talk about Java, what people do when the database is relational due to the object-relational impedance issue is to work with objects in the code and, of the two, or make the explicit conversion to SQL at hand (using JDBC) or maps more configuratively and automated using a ORM tool (such as JPA with Hibernate). This allows you to use an API that you have to persist an object of a certain type and it does the conversion. It’s interesting to abstract this in a Repository pattern, which is simply trying to provide a class that you use as if it were a container of objects in memory, like a list or dictionary, with its particular methods for adding, removing and locating objects of that type (in the case of the repository certain find methods are typical, such as findById, findAll) but underneath the cloth is being made the persistence of these database objects that in the code are being treated as being saved in a container. Note that it will be a repository for each type of object/situation in the code that requires data persistence, and the operations it provides will also be case-by-case. This interface provided by the repository is also expected to be agnostic to the database type (for example, it does not support Features that are only present in one or another database type).

But it seems to me that none of this will be useful in your case. Leandro Souza’s answer says it is, but I’m not sure. It seems to go because it’s being suggested to implement in a different way for every kind of repository that’s needed, that is, for every situation in the code, so I believe it would, but I understood that it’s not what you were imagining in your question, You wanted an even greater use of code. If I got it wrong, then this Repository proposal should work.

For a slightly more detailed discussion of the cons of having a general case of persistence for relational and non-relational (in English), see: https://stackoverflow.com/a/31941038/2241463

Browser other questions tagged

You are not signed in. Login or sign up in order to post.