Lançamento do meu livro de MongoDB


Foi em 2015 que conheci MongoDB. Sim, eu estava bem atrasado considerando que a tecnologia havia sido lançada em 2009 e desde 2010 já existiam grandes projetos usando-a. Como sempre gostei de criar aplicações com massas grandes de dados, como meus mecanismos de busca, logo me interessei pelo approach baseado em documentos do Mongo e facilidade de consultar. E pela performance, é claro.

Assim como fiz em 2012, conforme ia iniciando meus estudos de Android, fui documentando tudo o que aprendia e testava sobre MongoDB, ao mesmo tempo que estudava e aplicava outra tecnologia em meus projetos: Node.js.

Obviamente não comecei meus estudos partindo do zero, uma vez que já trabalho com sistemas que usam bancos de dados há cerca de 10 anos. Todo o meu conhecimento de banco de dados (que engloba muito SQL Server e um pouco de outros bancos), aliado às boas práticas de Engenharia de Software, Gestão de Projetos, Testes de Software, etc formaram o profissional que sou hoje.

No uso de MongoDB eu tenho experiência de mais de dois anos na data que escrevo este post e uma meia dúzia de projetos entregues e funcionando.

Pois então que há alguns meses decidi escrever um novo livro. O segundo de 2017 (o primeiro foi sobre Node.js), justamente sobre todo esse conhecimento de MongoDB que possuo que já me renderam algumas ofertas de emprego bem interessantes e alguns milhares de reais em projetos entregues usando este banco de dados.

Esse livro chama-se MongoDB para Iniciantes, e está à venda desde essa semana na Amazon.

Apesar do seu tamanho, 120 páginas, é um livro bem completo. Ele não se limita a listar e explicar comandos para consultar e manipular o MongoDB. Ele parte do princípio que você quer entender como funciona a orientação à documentos, que quer saber como se gerencia minimamente um servidor Mongo. Com uma didática clara e objetiva, como todos livros de minha autoria (quem já leu os demais sabe do que estou falando), e que pega o leitor pela mão e ensina desde os conceitos mais básicos até tudo que é necessário para ter um banco modelado corretamente e rodando, pronto para suas aplicações se conectarem. Inclusive ensina como usar MongoDB com Node.js, ASP.NET Core e PHP, sem entrar em muitos detalhes destas linguagens.

Do primeiro insert até comandos mais elaborados para manipulação de campos multi-valorados, índices, relatórios de performance e subdocumentos, MongoDB para Iniciantes é para quem está começando a trabalhar com MongoDB e bancos relacionais e está completamente confuso com a quantidade de tutoriais, informações conflitantes e artigos fora de ordem. Nele, ensino a usar tudo o que deu certo em meus projetos com MongoDB nos últimos anos, um banco não-relacional que é bom, confiável e que possui grande mercado.

Neste livro você vai aprender:

  • introdução aos bancos não-relacionais e NOSQL;
  • execução do servidor MongoDB;
  • conexão usando o client nativo Mongo;
  • quando usar e quando não usar MongoDB;
  • comandos básicos e intermediários para consultas;
  • comandos básicos e intermediários para inserção, atualização e exclusão de documentos;
  • como extrair relatório de performance de suas queries;
  • criação de índices;
  • gerenciamento mínimo de servidor (backup, restore, import);
  • como modelar os seus documentos usando o paradigma do MongoDB;
  • como criar aplicações reais usando Node.js, PHP e ASP.NET Core;
  • dezenas de boas práticas com MongoDB;

Novamente, devido às atualizações constantes, optei apenas por ter somente versão digital, que você pode ler no Kindle, no PC usando o ler.amazon.com e no smartphone/tablet usando o app Kindle Cloud Reader. Livros de tecnologia impressos tendem a ficar obsoletos rapidamente, coisa que eu detesto.

Além disso, caso assine o Kindle Unlimited (primeiro mês grátis e depois R$20/mês), você pode ler o meu livro e milhares de outros títulos gratuitamente.

Se ainda não é cliente da Amazon, esta é uma excelente oportunidade de começar com o pé direito. Modéstia à parte. 😉

Leia a amostra grátis do livro abaixo e tire suas próprias conclusões:

Tutorial MongoDB para iniciantes em NoSQL – Parte 5

MongoDB Logo
MongoDB Logo

E chegamos ao quinto artigo da minha série de tutoriais de MongoDB para iniciantes em NoSQL. Caso esteja caindo de pára-quedas nesta série, seguem os links dos posts e seus respectivos assuntos:

Neste quinto artigo tratarei de como manipular documentos que possuam subdocumentos e campos multivalorados, usando como base o banco de blog que modelamos no artigo anterior.

CRUD com Subdocumentos

No segundo artigo desta série nós vimos como buscar, inserir, atualizar e excluir documentos em coleções MongoDB. No entanto, sempre com documentos planos, sem níveis, a forma mais básica de armazenar dados.

Mas e quando temos um subdocumento dentro de outro documento, assim como o autor dentro de um artigo de blog?

Vamos começar pelo C do CRUD, que no caso do MongoDB é representado pelo método insert. O comando abaixo insere um novo artigo incluindo o subdocumento ‘autor’:

Note que eu não passo o _id do artigo pois ele é autoincremental e controlado pelo próprio MongoDB. Já no caso do autor, ele pertence à outra coleção, a de autores, e o _id que está junto dele deve ser o mesmo do autor original na sua referida coleção. Imagina-se que em uma aplicação que salve um artigo, que a informação do autor do artigo esteja em sessão ou em um componente de tela para ser passada ao MongoDB corretamente.

Falando do R do CRUD, o find no MongoDB, podemos facilmente usar campos de subdocumentos como filtros em nossas consultas, como segue:

Essa consulta retorna todos os artigos cujo nome do autor seja literalmente Luiz. Qualquer filtro existente pode ser usado aqui, sobre qualquer campo do subdocumento autor, mas atenção à forma que referenciei o campo, usando o nome do subdocumento, seguido de um ‘.’, e depois o nome do campo. Repare também que neste caso o uso de aspas ao redor da expressão é obrigatório.

Seguindo com o U do CRUD, vale tudo o que vimos até agora. Para substituir documentos que possuam subdocumentos usando o comando update, você tem de passar eles também, para não se perderem na atualização, como abaixo:

Se for usar um campo de um subdocumento no filtro do update, valem as mesmas regras do filtro do find que expliquei anteriormente. O mesmo vale caso queira aplicar algum update operator em um campo de um subdocumento. Quer um exemplo prático?

Na modelagem de blog que fizemos no post anterior, replicamos o nome e _id do autor em todos os posts escritos por ele. Mas o que acontece caso o nome do autor seja alterado no documento original dele, que fica na coleção de autores?

Teremos de replicar esta alteração em todos os artigos que tenham sido escritos por aquele autor, como abaixo. Neste exemplo, suponha que o autor Luiz teve o nome alterado para Luiz Fernando, então temos de atualizar todos os posts escritos por ele. Como é somente esta pequena informação que mudou, usaremos o update-operator $set, para não ter de sobrescrever os documentos inteiros.

Para um update mais preciso, eu poderia substituir o filtro autor.nome por autor._id, considerando que nomes de autores podem ser repetir em um mesmo blog.

Com os update-operators $set, $unset e $rename é possível manipular os campos dos subdocumentos também, da mesma forma que faria com o documento principal, apenas usando a notação “subdocumento.campo”.

Finalizando o CRUD com subdocumentos, o D de delete é realizado usando as mesmas regras de filtro do find, caso queira excluir todos os documentos que possuam um valor específico em um campo de um subdocumento. Sem mistério algum.


CRUD com campos multivalorados

Outra preocupação é com a manipulação de elementos em campos multi-valorados, algo inexistente em bancos relacionais que sempre assumem relações 1-N ou N-N nestes casos. Salvo gambiarras que já vi por aí de salvar strings CSV ou JSON em coluna de registro e outras loucuras que sempre acabam gerando dor de cabeça pois não são pesquisáveis.

Começando pelo C do CRUD, o insert do MongoDB funciona de maneira muito óbvia para campos multivalorados: apenas passe null para nenhum valor ou o array (entre colchetes) de valores iniciais daquele elemento (sim, o MongoDB permite que depois você adicione ou remova elementos).

Se você procurar no exemplo anterior de insert, verá que passei null no campo multivalorado de tags do artigo. A outra opção, passando valores iniciais, segue abaixo:

Neste caso o campo multivalorado tags é um array de strings. Caso deseje, você pode inserir um documento que possua campos multivalorados de documentos também, como no caso das categorias que modelamos no post anterior:

Mas é quando entramos no R do CRUD com campos multivalorados em MongoDB que começamos a explorar um novo universo de possibilidades e novos filter-operators da função find.

Considere que temos três artigos salvos na nossa base MongoDB (omitirei os campos que não nos importam no momento):

Para fazer buscas usando campos multivalorados como filtro é muito simples: você deve usar os operadores de filtro $all e $in. Exemplo de consulta por todos os artigos que possuam todas (ALL) as seguintes tags NodeJs e MongoDB :

O operador $all vai garantir que só sejam retornados artigos que possuam no mínimo as duas tags informadas (somente o Artigo 1), equivalente à consulta SQL abaixo:

Agora um exemplo de consulta por todos os artigos que possuam uma (IN) das seguintes tags NodeJs ou MongoDB:

Neste caso todos os três artigos serão retornados, assim como no equivalente SQL abaixo (coloquei reticências por preguiça de preencher todas as colunas):

Mas agora se quisermos apenas os artigos que possuam ao menos uma categoria (o campo de categorias é multivalorado, lembra?) com o nome Desenvolvimento?

Quando aplicamos um filtro sobre um campo que é multivalorado o MongoDB entende que podemos passar um novo filtro a seguir, que será aplicado aos campos do subdocumento. Por exemplo:

Vai retornar todos os documentos que tenham ao menos uma categoria cujo nome seja ‘Desenvolvimento’. Também poderia usar filter-operators se fosse necessário como $gte, $regex, etc.

Avançando para o U do CRUD, no update de campos multivalorados também temos diversas opções a serem exploradas pois é no update que adicionamos e removemos elementos do nosso array, quando quisermos fazê-lo. Para tais tarefas deve-se usar os operadores $pull (remove o elemento do array) e $push (insere o elemento no array), sempre dentro de um comando de update, como segundo parâmetro (update-operator). Ex:

Pode parecer um pouco estranho no início, mas na verdade é muito mais simples, pois é a mesma ideia que já fazemos há anos com coleções em linguagens de programação, onde geralmente temos métodos como add e remove ou assemelhados.

Finalizando, o D do CRUD, em campos multivalorados funciona da mesma forma que o find, considerando que no deleteOne e deleteMany do MongoDB também passamos um filtro por parâmetro.

Quer aprender outras dicas? Leia o que escrevi sobre boas práticas com MongoDB no blog da Umbler!

Curtiu o post? Que tal aprender a usar MongoDB com Node.js? Então clica no banner abaixo e dá uma conferida no meu livro sobre programação web com Node.js!

Tutorial MongoDB para iniciantes em NoSQL – Parte 4

MongoDB Logo
MongoDB Logo

E chegamos ao quarto artigo da minha série de tutoriais de MongoDB para iniciantes em NoSQL. Caso esteja caindo de pára-quedas nesta série, seguem os links dos posts e seus respectivos assuntos:

Neste quarto artigo tratarei de um tópico complicado, denso e muitas vezes controverso: modelagem de dados orientada a documentos.

Me basearei aqui em experiências próprias de mais de dois anos trabalhando com esta tecnologia, em projetos de todos os tamanhos, além das guidelines oficiais, obviamente. Ao invés de ficar falando sobre como você deve modelar, usarei uma didática baseada em comparação entre exemplos com modelos relacionais famosos para auxiliar na assimilação dos conhecimentos.

Preparado para finalmente entender como modelar seus bancos MongoDB?

Veremos neste artigo:

Princípios importantes

Primeiramente, tenha a mente aberta. Entenda que tudo que você aprendeu nas disciplinas de banco de dados da faculdade estão certas, mas em outro contexto, não nesse. Que as Formas Normais não significam nada aqui.

Eu tive a sorte de ter conhecido o MongoDB em um projeto já maduro que rodava há três anos e tinha muitos dados. Com isso, já aprendi do “jeito certo”, pois quando você cria um banco em um projeto pequeno, qualquer modelagem funciona e é difícil de imaginar como algumas decisões realmente podem lhe afetar no futuro.

O primeiro ponto a entender, e que muitas se recusam veemente é que você deve evitar relacionamentos entre documentos diferentes. Apesar dos avanços neste sentido nas últimas versões do MongoDB, este ainda é um banco não-relacional e, portanto, não faz sentido algum modelá-lo pensando em relacionamentos.

O segundo ponto é que documentos não são equivalentes a linhas de banco de dados. Essa é uma comparação muito simplória e que tende a levar ao erro. Documentos são entidades auto-suficientes, com todas as informações que lhes competem. Uma analogia que me ajuda a pensar nos documentos do jeito certo são as INDEXED VIEWS dos bancos relacionais. O plano é que, na maioria das consultas, com um filtro e sem “JOIN” algum, você consiga trazer todos os dados que necessita para montar uma tela de sua aplicação.

O terceiro e último ponto é manter simples. Não é porque o MongoDB permite que você aninhe até 100 níveis de subdocumentos dentro de um documento que você deve fazê-lo. Não é porque o MongoDB permite até 16MB por documento que você deve ter documentos com este tamanho. Não é porque você pode ter até 64 índices por coleção que você deve ter tudo isso. Essas e outras limitações estão lá na documentação oficial.

MongoDB não é magia, encare ele com a mesma seriedade que encara os bancos relacionais e estude bastante. A curva de aprendizagem inicial é realmente mais simples do que SQL, mas a longo prazo, é tão difícil quanto. Como já mencionei no post sobre persistência poliglota, os bancos não-relacionais não são melhores que os relacionais. Eles não eliminam os problemas dos relacionais, ao invés disso eles possuem os seus próprios problemas.

Para que você entenda tudo isso na prática, preparei um case simples de banco de dados que é bem comum, enquanto que futuramente espero ter tempo para apresentar cases mais complexos. Obviamente podem haver variações tanto na implementação relacional citada aqui, quanto a não-relacional que eu sugeri. Se apegue mais às ideias do que aos detalhes e use a seção de comentários para discutirmos o que você não concorda e/ou não entendeu.

Modelagem de Blog: Relacional

Bom, você está em um blog neste exato momento, então nada que eu disser aqui será uma novidade para você. Um blog possui basicamente artigos com id, título, data de publicação, conteúdo, categorias, tags, autor, status (rascunho, agendado, publicado, etc) e URL. As categorias possuem id, nome e descrição. Os autores possuem id, nome, foto, permissões, usuário, senha e bio. Além disso, temos os comentários. Ah os comentários, possuem toda uma complexidade própria: autor, data, texto, etc.

Em um banco relacional, como faríamos? (note que uso tabelas no singular e sem prefixos)

  • Tabela 1: Artigo, com ID (PK), Titulo (NVARCHAR), DataPublicacao (DATETIME), Conteúdo (NVARCHAR), IDAutor (FK), Status (INT – considerando um enumerador) e URL (NVARCHAR). Esta é a tabela principal e como era de esperar, o IDAutor vai referenciar outra tabela. Mas cadê tags e categorias?
  • Tabela 2: Autor, com ID (PK), Nome (NVARCHAR), Bio (NVARCHAR), Foto (NVARCHAR – porque guardarei apenas o caminho da foto), Usuario (NVARCHAR, unique) e Senha (NVARCHAR)
  • Tabela 3: Categoria, com ID (PK), Nome (NVARCHAR) e Descricao (NVARCHAR). A descrição é útil nas páginas de posts de uma mesma categoria.
  • Tabela 4: ArtigoCategoria, com ID (PK), IDArtigo (FK), IDCategoria (FK). Um artigo pode ter várias categorias e cada categoria pode estar em vários artigos, o clássico “N para N”, um câncer dos bancos relacionais na minha opinião.
  • Tabela 5: Tag, com ID (PK), IDArtigo (FK), Nome (NVARCHAR). Aqui podemos fazer um “1 para N”, onde cada artigo pode ter várias tags ou um “N para N”, se quiser a não-repetição dos nomes de tags.
  • Tabela 6: Comentario, com ID (PK), IDArtigo (FK), Nome (NVARCHAR – autor do comentário), Texto (NVARCHAR – o comentário em si), Data (DATETIME).

Pode ser mais complexo e poderoso que isso, mas vamos manter assim, visto que o objetivo aqui não é modelar o melhor banco de dados para blogs do mundo, mas sim apenas para mostrar como uma modelagem dessas pode ser feita em um banco relacional e em um não-relacional no mesmo post.

Diagrama ER Blog
Diagrama ER Blog

Considerando o banco descrito acima, como faríamos para montar uma tela de uma postagem completa no site do blog?

Essa consulta traz as informações do Artigo e de seu Autor (só o que importa do autor para a página do post). Mas e as tags e categorias? Precisamos de mais duas consultas para isso:

Puxa, esqueci dos comentários ainda, certo? Vamos trazê-los também!

Com isso conseguimos finalmente montar uma página bem simples, com apenas uma postagem de um blog. Precisamos de 4 consultas com 2 JOINs diferentes.

Complicado, não?!

E no MongoDB, como ficaria isso?


Modelagem de Blog: Não-Relacional

Em bancos de dados não-relacionais, o primeiro ponto a considerar é que você deve evitar relacionamentos, afinal, se for pra usar um monte de FK, use SQL e seja feliz!

A maioria das relações são substituídas por composições de sub-documentos dentro de documentos, mas vamos começar por partes. Primeiro, vamos criar um documento JSON que represente o mesmo artigo do exemplo anterior com SQL (dados de exemplo apenas), como pertencendo a uma coleção Artigo:

Primeira diferença: aqui os IDs não são numéricos auto-incrementais, mas sim ObjectIds auto-incrementais. Segunda diferença: não há schema rígido, então eu posso ter artigos com mais informações do que apenas estas, ou com menos. Mas e aquele idAutor ali?

Se eu colocar daquele jeito ali, com idAutor, quando eu for montar a tela do artigo eu sempre teria de ir na coleção de Autores para pegar os dados do autor, certo? Mas se eu sei quais informações eu preciso exibir (apenas nome e id, assim como na consulta SQL), o certo a se fazer aqui é reproduzir estas informações como um subdocumento de artigo, como abaixo:

Esse é o jeito “certo” de fazer com MongoDB! Note que o subdocumento autor possui apenas os dados necessários para montar uma tela de artigo. Mas se precisarmos depois da informação completa do autor, podemos pegá-la a partir de seu id.

Como MongoDB não garante integridade referencial por não possuir FK, temos de tomar muito cuidado quando você for excluir um autor, para desvinculá-lo em todos os artigos dele, e quando você for atualizar o nome dele, para atualizar em todos artigos dele.

Já a coleção Autor, fica com documentos bem parecidos com a tabela original em SQL:

Note que aqui eu não vou embutir todos os artigos deste autor, pois seria inviável. O foco do blog são os artigos, não os autores, logo, os artigos vão conter o seu autor dentro de si, e não o contrário!

Um adendo: MongoDB trabalha muito bem com arquivos binários embutidos em documentos, então se quisesse usar um binário de imagem no campo foto, funcionaria perfeitamente bem, melhor que no SQL tradicional (BLOBs, arghhh!).

Mas e as categorias e tags? Como ficam?

Primeiro que aqui não precisamos de tabelas-meio quando temos relacionamento N-N. Todos os relacionamentos podem ser representados na modalidade 1-N usando campos multivalorados, como mostrado no exemplo abaixo, de uma v3 do documento de artigo:

Tags são apenas strings tanto na modelagem relacional original quanto nesta modelagem orientada a documentos. Sendo assim, um campo do tipo array de String resolve este cenário sem maiores problemas.

Já as categorias são um pouco mais complexas, pois podem ter informações extras como uma descrição. No entanto, como para exibir o artigo na tela do sistema nós só precisamos do nome e do id das categorias, podemos ter um array de subdocumentos de categoria dentro do documento de artigo.

Em paralelo deveremos ter uma coleção de categorias, para armazenar os demais dados, mantendo o mesmo ObjectId:

Novamente, caso no futuro você venha a excluir categorias, terá de percorrer toda a coleção de artigos visando remover as ocorrências das mesmas. No caso de edição de nome da categoria original, também. Com as tags não temos exatamente este problema, uma vez que elas são mais dinâmicas.

Para encerrar, temos os comentários. Assim como fizemos com as categorias, vamos embutir os documentos dos comentários dentro do documento do artigo ao qual eles fazem parte, afinal, não faz sentido algum eles existirem alheios ao artigo do qual foram originados.

Note que aqui optei por ter um _id no comentário, mesmo ele não possuindo uma coleção em separado. Isso para que seja possível mais tarde moderar comentários.

E esse é um exemplo de documento completo, modelado a partir do problema de um site de artigos, blog, wiki, etc.

Ah, mas e como fazemos a consulta necessária para montar a tela de um artigo? Lembra que em SQL eram inúmeras consultas cheias de INNER JOINs? No MongoDB, precisamos de apenas uma consulta, bem simples, para montar a mesma tela:

Essa consulta traz os mesmos dados que todas aquelas que fiz em SQL juntas. Isso porque a modelagem dos documentos é feita sem relacionamentos externos, o documento é auto-suficiente em termos de dados, como se fosse uma VIEW do SQL, mas muito mais poderoso.

Claro, existem aqueles pontos de atenção que mencionei, sobre updates e deletes, uma vez que não há uma garantia nativa de consistência entre coleções. Mas lhe garanto, a performance de busca é incomparável, uma vez que a complexidade é baixíssima. Você inclusive pode criar um índice no campo url da coleção Artigo, para tornar a busca ainda mais veloz, com o comando abaixo:

Demais, não?!

Você pode estar preocupado agora com a redundância de dados, afinal diversas strings se repetirão entre os diversos anúncios, como o nome do autor, tags, nomes de categoria, etc. Não se preocupe com isso, o MongoDB trabalha muito bem com volumes muito grandes de dados e desde que você tenha bastante espaço em disco, não terá problemas tão cedo. Obviamente não recomendo que duplique conteúdos extensos, mas palavras como essas que ficaram redundantes na minha modelagem não são um problema.

No entanto, lidar com subdocumentos e campos multivalorados adiciona um pouco mais de complexidade à manipulação do MongoDB, e trato disso nesse post que é continuação da série!

Quer aprender outras dicas? Leia o que escrevi sobre boas práticas com MongoDB no blog da Umbler!

Curtiu o post? Que tal aprender a usar MongoDB com Node.js? Então clica no banner abaixo e dá uma conferida no meu livro sobre programação web com Node.js!