Um pouco de schema design no MongoDB

MongoDB

MongoDB

Fico realmente surpreso ao ver a grande adoção do MongoDB no Brasil! Viajo bastante para palestrar sobre o assunto, vejo que público só aumenta, assim como alto nível das perguntas. Isso mostra que o MongoDB está sendo bem estudado e colocado em prática por muita gente.

A dúvida mais comum é em relação a modelagem e relacionamento. Vejamos, o MongoDB é considerado um banco de dados não relacional, com isso, não é necessário fazer uma espécie de “CREATE TABLE” para começar inserir dados. E quanto relacionar um registro com outro? Bom, para isso é necessário pensar de forma não relacional, como vou mostrar a seguir.

Qual melhor modelagem para MongoDB?

É lógico que cada aplicação é uma aplicação, tem suas necessidades e particularidades. Vou expor aqui o exemplo que apresentei na última Latinoware: uma aplicação de Escola, com uma coleção de alunos e uma coleção de biblioteca, sendo que essa aplicação deve fazer o controle de empréstimos dos livros aos seus alunos. Sempre que um livro é retirado, precisamos informar qual foi o aluno que retirou esse livro, quando e quanto tempo ele ficou com o livro emprestado. Também podemos adicionar mais informações, como atraso na entrega do livro, multas, se voltou danificado, etc.

Fazer isso no PostgreSQL ou MySQL é bem simples, quem pensa de forma relacional já imaginou pelo menos três tabelas: alunos, livros e empréstimos, onde a tabela de empréstimos possui o id do aluno que retirou, o id do livro retirado e outros campos complementares.

E no MongoDB, como fazer isso?

Vou detalhar de forma bem simples, umas coleções (equivalente a tabela no MongoDB) com o mínimo possível de informações para ilustrar esse exemplo.

A coleção de alunos:

Vamos imaginar a coleção de alunos com os seguintes dados:

{ "_id" : "carolina.alves", "nome" : "Carolina", "sobrenome" : "Alves" }
{ "_id" : "joao.paulo", "nome" : "Joao", "sobrenome" : "Paulo" }
{ "_id" : "rafael.borges", "nome" : "Rafael", "sobrenome" : "Borges" }

Repare que está bem simples, troquei o ObjectID padrão por uma espécie de login de cada usuário para facilitar a visualização.

A coleção de livros

{ "_id" : "00001", "titulo" : "O Principe", "autor" : "Nicolau Maquiavel" }
{ "_id" : "00002", "titulo" : "A Arte da Guerra", "autor" : "Sun Tzu" }
{ "_id" : "00003", "titulo" : "A Republica", "autor" : "Platao" }

Também só o mínimo possível de informações para ilustrar o exemplo

Controlando empréstimo de livros

Agora vem a parte divertida. Como fazer no MongoDB o controle de empréstimos de livros para os alunos e assim gerenciar o acervo da biblioteca?

Bom, existem algumas forma de se pensar. Vou detalhar a minha favorita abaixo, mas depois vou citar outras possibilidades também. O grande segredo de uma boa modelagem no MongoDB é pensar na aplicação como um todo e ver a melhor maneira de extrair a maior quantidade de informações em um único find.

Como o objeto de interesse é controle de livros, então a coleção de livros é que será modificada para agregar as funções de empréstimos, vamos supor o seguinte cenário:

A aluna Carolina Alves retirou o livro O Príncipe por 5 dias.

Para fazer esse controle, nós vamos adicionar à coleção livros uma chave chamada “aluguel”, composta de múltiplos valores, ficaria assim:

> db.livros.update({'_id':'00001'},
... {$set: {'aluguel': {
... 'aluno_id':'carolina.alves',
... 'periodo': {'inicio':'2013-11-30','fim':'2013-12-05'}}}})

Desta forma, todos os livros alugados terão a chave aluguel, que é composta de valores que podem ser adicionados de acordo com cada necessidade.

Isso facilita a consulta por todos os livros alugados, o find abaixo é um exemplo dessa consulta:

> db.livros.find({'aluguel':{$exists: true}})

E o resultado:

{
    "_id" : "00001",
    "aluguel" : {
        "aluno_id" : "carolina.alves",
        "periodo" : {
            "inicio" : "2013-11-30",
            "fim" : "2013-12-05"
        }
    },
    "autor" : "Nicolau Maquiavel",
    "titulo" : "O Principe"
}

E o find abaixo mostra apenas os livros disponíveis na biblioteca:

db.livros.find({'aluguel':{$exists: false}})

Seguindo essa lógica, assim que a aluna devolver o livro, basta remover a chave “aluguel” da coleção livro que o mesmo volta a ficar como disponível na biblioteca.

Também o conteúdo da chave aluguel pode ser movida para outra chave como por exemplo, historico_de_alugueis, dessa maneira mantém um histórico de quem foram os alunos que fizeram retiradas, assim também gerar estatísticas de tempo médio de retirada, quais foram os livros mais retirados, quem pagou multa, quais alunos mais retiram livros, etc.

Essa é a maneira que eu faria uma aplicação desse porte.

Outras formas

Existem outras maneiras de fazer a mesma coisa:

  1. Criar o controle na coleção de aluno. Não gosto dessa maneira porque se alguém quiser saber quais são os livros alugados, terá que varrer toda a coleção de alunos procurando por essa chave.

  2. Criar uma outra coleção de controle, onde relaciona o id do aluno + id do livro com outras informações. Essa é a pior maneira para o MongoDB, pois é um jeito muito relacional de se pensar. E também terá que fazer pelo menos 3 queries, uma para identificar o aluno através de seu id, outra para identificar o livro através de seu id e outra para exibir as informações adicionais.

Schema design não é complicado, o grande segredo é entender como o MongoDB trabalha com as informações para modelar de maneira mais adequada. É necessário também pensar na aplicação, como você extrai o maior número de dados com apenas um find? Sabendo responder essa pergunta, o sucesso da aplicação acontece naturalmente.

Pretendo escrever mais artigos desse nível. Se você tem algum comentário, dúvida ou sugestão, fique à vontade para comentar aqui no post.

Espero que tenha gostado!


Veja também