Construindo com padrões: o padrão de collection única
Avalie esse Artigo
Em um artigo anterior sobre modelagem de dados, descrevemos diferentes tipos de dados e como eles se comportam com a duplicação de dados. Um relacionamento de muitos para muitos com dados que não consegue manter a duplicação de dados pode não ser um bom candidato para incorporar o relacionamento ou aplicar o Padrão de Referência Estendida. No entanto, há outra maneira de otimizar esse relacionamento ao trabalhar com o modelo de documento .
O padrão Single Collection é baseado no padrão Single Table e adaptado para o modelo de documento . O padrão Single Table foi descrito extensivamente pelos funcionários da Amazon. Ele é usado em muitos aplicativos DynamoDB para reduzir custos, melhorar o desempenho e evitar algumas das armadilhas comuns que os desenvolvedores encontram nos bancos de dados NoSQL.
O padrão às vezes é chamado de Padrão de Adjacência. O padrão Single Collection agrupa documentos relacionados de diferentes tipos em uma única collection. Caso contrário, os documentos estariam em várias coleções.
Três características definem o padrão:
- Todos os documentos relacionados que são acessados com frequência juntos são armazenados na mesma coleção.
- As relações entre os documentos são armazenadas como ponteiros ou outras estruturas dentro do documento.
- Um índice é construído no campo ou array que mapeia os relacionamentos. Esse índice suporta a recuperação de todos os documentos relacionados em uma única query sem operações de junção de banco de dados .
O padrão ajuda a modelar relacionamentos de muitos para muitos, permitindo que se mantenha apenas uma cópia das informações. Isso evita o uso da duplicação de dados onde o custo da duplicação excede os benefícios.
Há um cenário adicional em que esse padrão se destaca. Esse é o caso em que atualizações frequentes são feitas em documentos grandes. Ao dividir o documento em partes menores, um mecanismo de banco de dados que reescreve todo o documento no disco para cada alteração pode realizar operações de gravação menores e melhorar o desempenho.
Se o padrão for usado para modelar um relacionamento muitos-para-muitos , é necessário usar uma array de referências e manter essas referências bidirecionalmente, pelo menos uma referência a si mesmo, conforme mostrado no exemplo mais abaixo. Para os outros tipos de relacionamento, pode-se alternativamente construir o relacionamento por meio de um único campo. Por exemplo, considere um cliente que tenha muitos pedidos, e cada pedido tenha muitos itens de linha. Podemos criar um campo
_id
contendo as informações de cada tipo de documento e a relacionamento desse documento com o documento pai .1 { 2 "_id": "C12345", 3 "doc_type": "customer", 4 ... 5 } 6 7 { 8 "_id": "C12345-I34562", 9 "doc_type": "invoice", 10 ... 11 } 12 13 { 14 "_id": "C12345-I34562-L0001", 15 "doc_type": "line item", 16 ... 17 }
Uma query como essa recuperaria uma fatura e todos os seus itens de linha.
1 find({"_id": /^C12345-I34562/})
Vamos usar um aplicação que permita aos alunos ver o status das aulas que seguem em um determinado semestre. Um documento de classe será a instância específica da classe, em outras palavras, a classe ministrada por um professor em determinado momento. A entidade primária do nosso sistema é o aluno. Esta é a entidade central consultada pelo sistema.
Se fôssemos incorporar um lado da relacionamento, seriam as classes, a entidade secundária. Como o sistema atualiza muitos itens sobre uma classe, como a próxima sessão e o resumo da sessão anterior, não queremos duplicar as informações de cada aluno. Faz sentido manter as entidades separadas, mas vamos aplicar o Padrão de Coleção Única.
1 { 2 "_id": "CS101-001", 3 "doc_type": "class", 4 "class_name": "Introduction to Programming", 5 "course_id": "CS101", 6 "instructor": { 7 "name": "Dr. Emily Smith", 8 "email": "emily.smith@example.com", 9 "office_hours": "Tuesdays and Thursdays 2:00 PM - 4:00 PM" 10 }, 11 "semester": "Spring 2025", 12 "schedule": [ 13 { 14 "day_time": "Monday 10:00 AM - 11:30 AM", 15 "location": "Room 101, Science Building" 16 }, 17 { 18 "day_time": "Wednesday 10:00 AM - 11:30 AM", 19 "location": "Room 101, Science Building" 20 }, 21 { 22 "day_time": "Friday 10:00 AM - 11:30 AM", 23 "location": "Room 101, Science Building" 24 } 25 ], 26 "current_topic": "Loops and Iterations", 27 "next_class_time": "2025-01-09T10:00:00Z", 28 "upcoming_session_summary": "We will explore different types of loops (for, while) and how to use them effectively in Python.", 29 "links": [ 30 { "target": "CS101-001", "doc_type": "class" }, 31 { "target": "S10023", "doc_type": "student" }, 32 { "target": "S12345", "doc_type": "student" }, 33 ... 34 { "target": "S12355", "doc_type": "student" } 35 ] 36 }
Observe que
doc_type
os target
campos e na links
array nos permitem manter o relacionamento entre nossas entidades e filtrá-las por tipo de documento .Exemplo de documento de um aluno :
1 { 2 "_id": "S12345", 3 "doc_type": "student", 4 "name": "Jane Doe", 5 "major": "Computer Science", 6 "semester": "Spring 2025", 7 "registered_classes": [ 8 { 9 "course_id": "CS101", 10 "class_instance_id": "CS101-001", 11 "class_name": "Introduction to Programming" 12 }, 13 { 14 15 "course_id": "MATH201", 16 "class_instance_id": "MATH201-002", 17 "class_name": "Calculus II" 18 } 19 ], 20 "links": [ 21 { "target": "CS101-001", "doc_type": "class" }, 22 { "target": "MATH201-002", "doc_type": "class" }, 23 { "target": "S12345", "doc_type": "student" } 24 ] 25 }
Se não houver necessidade de fazer query de todos os alunos de uma determinada classe, a
links
array não precisará incluir ponteiros para as turmas. No entanto, ele precisa ter uma referência a si mesmo para que uma query possa retornar um documento de "estudantes" e todos os documentos de "classes" associados.Em seguida, indexamos a
links
estrutura do para otimizar as queries.1 db.students_classes.createIndex({"links.target":1, "links.doc_type": 1})
A query a seguir recupera um aluno e todas as aulas que ele faz sem fazer nenhuma união, fornecendo o melhor desempenho.
1 db.students_classes.find({"links.target": "S12345"})
A query a seguir recupera todos os alunos registrados na classe CS101-001.
1 db.students_classes.find({"doc_type": "student", "links.target": "CS101-001"})
A Single Collection é ideal para modelar sistemas com operações de alta velocidade, requisitos de baixa latência e operações de escrita frequentes. Por exemplo, adicionar dados em bits e chunks a documentos ao longo do tempo. Ao decompor um documento, você evita problemas de desempenho com mecanismos de armazenamento que reescrevem documentos completos após qualquer atualização. O outro cenário em que o padrão se destaca é sua capacidade de modelar relacionamentos muitos-para-muitos em que a duplicação de dados seria um problema significativo.
O lado negativo é que o padrão adiciona complexidade ao código e ao gerenciamento das referências. Deve-se preferir a incorporação ou o Padrão de Referência Estendida para os cenários em que a solução prefere a simplicidade ou a duplicação de dados é aceitável e gerenciável. Se o requisito de desempenho for a leitura de muitas seções de dados de uma só vez, preferiria-se pré-montar as diferentes partes dos dados em um documento com a forma a ser lida; em outras palavras, preferiria-se um documento maior onde as entidades estejam incorporadas.
Para saber mais sobre os outros padrões, consulte a lista neste resumo ou o livro MongoDB Data Modeling and Schema Design ou faça as aulas gratuitas de Modelagem de Dados na MongoDB University.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.