Como já foi escrito, não existem regras como a segunda forma normal para SQL.
No entanto, existem algumas práticas recomendadas e armadilhas comuns relacionadas à otimização para o MongoDB que listarei aqui.
Uso excessivo de incorporação
O limite de BSON
Ao contrário da crença popular, não há nada de errado com referências. Suponha que você tenha uma biblioteca de livros e queira acompanhar os aluguéis. Você poderia começar com um modelo como este
{
// We use ISBN for its uniqueness
_id: "9783453031456"
title: "Schismatrix",
author: "Bruce Sterling",
rentals: [
{
name:"Markus Mahlberg,
start:"2015-05-05T03:22:00Z",
due:"2015-05-12T12:00:00Z"
}
]
}
Embora existam vários problemas com este modelo, o mais importante não é óbvio – haverá um número limitado de aluguéis devido ao fato de que os documentos BSON têm um limite de tamanho de 16 MB.
O problema de migração de documentos
O outro problema com o armazenamento de aluguéis em uma matriz seria que isso causaria migrações de documentos relativamente frequentes, o que é uma operação bastante cara. Os documentos BSON nunca são particionados e criados com algum espaço adicional alocado antecipadamente usado quando crescem. Esse espaço adicional é chamado de preenchimento. Quando o preenchimento é excedido, o documento é movido para outro local nos arquivos de dados e um novo espaço de preenchimento é alocado. Portanto, adições frequentes de dados causam migrações frequentes de documentos. Portanto, é uma prática recomendada evitar atualizações frequentes aumentando o tamanho do documento e usar referências.
Então, para o exemplo, mudaríamos nosso modelo único e criaríamos um segundo. Primeiro, o modelo para o livro
{
_id: "9783453031456",
title:"Schismatrix",
author: "Bruce Sterling"
}
O segundo modelo para locação ficaria assim
{
_id: new ObjectId(),
book: "9783453031456",
rentee: "Markus Mahlberg",
start: ISODate("2015-05-05T03:22:00Z"),
due: ISODate("2015-05-05T12:00:00Z"),
returned: ISODate("2015-05-05T11:59:59.999Z")
}
A mesma abordagem, é claro, poderia ser usada para autor ou locatário.
O problema da normalização excessiva
Vamos olhar para trás algum tempo. Um desenvolvedor identificaria as entidades envolvidas em um caso de negócios, definiria suas propriedades e relações, escreveria as classes de entidade correspondentes, bateria a cabeça contra a parede por algumas horas para obter o trabalho triplo interno-externo-acima-e-além do JOIN necessário para o caso de uso e todos viveram felizes para sempre. Então, por que usar NoSQL em geral e MongoDB em particular? Porque ninguém viveu feliz para sempre. Essa abordagem escala horrivelmente e quase exclusivamente a única maneira de escalar é vertical.
Mas a principal diferença do NoSQL é que você modela seus dados de acordo com as perguntas que precisam ser respondidas.
Dito isto, vamos olhar para uma relação n:m típica e tomar a relação de autores para livros como nosso exemplo. Em SQL, você teria 3 tabelas:duas para suas entidades (livros e autores ) e um para a relação (Quem é o autor de qual livro? ). Claro, você pode pegar essas tabelas e criar suas coleções equivalentes. Mas, como não há JOINs no MongoDB, você precisaria de três consultas (uma para a primeira entidade, uma para suas relações e outra para as entidades relacionadas) para encontrar os documentos relacionados de uma entidade. Isso não faria sentido, já que a abordagem de três tabelas para relações n:m foi inventada especificamente para superar os esquemas rígidos que os bancos de dados SQL impõem. Como o MongoDB tem um esquema flexível, a primeira questão seria onde armazenar a relação, mantendo os problemas decorrentes do uso excessivo de incorporação em mente. Como um autor pode escrever vários livros nos próximos anos, mas a autoria de um livro raramente muda, a resposta é simples:armazenamos os autores como uma referência aos autores nos dados dos livros
{
_id: "9783453526723",
title: "The Difference Engine",
authors: ["idOfBruceSterling","idOfWilliamGibson"]
}
E agora podemos encontrar os autores desse livro fazendo duas consultas:
var book = db.books.findOne({title:"The Difference Engine"})
var authors = db.authors.find({_id: {$in: book.authors})
Espero que o acima o ajude a decidir quando realmente "dividir" suas coleções e contornar as armadilhas mais comuns.
Conclusão
Quanto às suas perguntas, aqui estão minhas respostas
- Como escrito antes:Não , mas manter as limitações técnicas em mente deve dar uma ideia de quando isso pode fazer sentido.
- Não é ruim – desde que se adeque ao(s) seu(s) caso(s) de uso . Se você tiver uma determinada categoria e seu
_id
, é fácil encontrar os produtos relacionados. Ao carregar o produto, você pode obter facilmente as categorias a que pertence, de forma ainda mais eficiente, como_id
é indexado por padrão. - Ainda não encontrei um caso de uso que não possa ser feito com o MongoDB, embora algumas coisas possam ficar um pouco mais complicadas com o MongoDB. O que você deve fazer é pegar a soma de seus requisitos funcionais e não funcionais e verificar se as vantagens superam as desvantagens. Minha regra geral:se um de "escalabilidade" ou "alta disponibilidade/failover automático" estiver na sua lista de requisitos, o MongoDB vale mais do que uma olhada.