Você precisa considerar o tipo de consultas que precisará realizar e com que frequência cada tipo será necessário. Quando estava trabalhando em algo semelhante, criei seis ações possíveis:
- Faça algo com o pai
- Faça algo com as crianças
- Faça algo com os ancestrais (pais dos pais, pais dos pais dos pais etc.)
- Faça algo com os descendentes (filhos de filhos, filhos de filhos de filhos, etc.)
- Alterar relacionamentos (adicionar/mover/excluir nós na hierarquia)
- Alterar os dados principais no nó atual (por exemplo, alterar o valor no campo "título")
Você desejará estimar a importância de cada um deles para sua aplicação.
Se a maior parte do seu trabalho envolve trabalhar com dados armazenados para um determinado artigo, incluindo seu pai e filho imediatos, a primeira ideia é mais útil. De fato, no MongoDB, é bastante comum colocar todas as informações de que você precisa no mesmo documento, em vez de referenciá-las externamente, de modo que você só precise recuperar uma coisa e trabalhar com esses dados. As últimas quatro ações da lista são mais complicadas.
Em particular, você precisará percorrer a árvore para recuperar ancestrais e descendentes neste caso, movendo-se por documentos intermediários e seguindo um caminho, mesmo que você só se importe com o último documento no caminho. Isso pode ser lento para hierarquias longas. A alteração dos relacionamentos pode exigir a movimentação de muitas informações em vários documentos devido a todos os dados presentes em cada um. Mas até mesmo alterar um único campo como "título" pode ser irritante, porque você deve considerar o fato de que esse campo está presente em vários documentos diferentes, seja como um campo principal ou sob os campos pai ou filho.
Basicamente, sua primeira ideia funciona melhor em mais aplicativos estáticos onde você não mudará muito os dados depois de criá-los inicialmente, mas onde você precisa lê-los regularmente.
A documentação do MongoDB tem cinco abordagens recomendadas para lidar com estruturas semelhantes a árvores (hierárquicas). Todos eles têm vantagens e desvantagens diferentes, embora todos facilitem a atualização dos dados principais em um artigo, bastando fazê-lo em um documento.
- Referências dos pais :cada nó contém uma referência ao seu pai.
- Vantagens :
- Pesquisa rápida de pai (pesquisa por "_id" =título do seu documento, retorne o campo "pai")
- Pesquisa rápida de filhos (pesquisa por "pai" =título do seu documento, que retornará todos os documentos filhos)
- Atualizar relacionamentos é apenas uma questão de alterar o campo "pai"
- Alterar os dados subjacentes requer alterações em apenas um documento
- Desvantagens :
- A pesquisa por ancestrais e descendentes é lenta, exigindo uma travessia
- Referências secundárias :cada nó contém um array de referência para seus filhos
- Vantagens :
- Recuperação rápida de filhos (retorne a matriz de filhos)
- Atualização rápida de relacionamento (apenas atualize a matriz dos filhos quando necessário)
- Desvantagens :
- Encontrar um pai requer procurar seu _id em todos os arrays filhos de todos os documentos até encontrá-lo (já que o pai conterá o nó atual como filho)
- A pesquisa de ancestrais e descendentes requer travessias da árvore
- Vantagens :
- Matriz de Ancestrais :cada nó contém uma referência a um array de seus ancestrais e seu pai
- Vantagens :
- Recuperação rápida de ancestrais (não é necessário percorrer para encontrar um específico)
- Facilidade de pesquisar pais e filhos seguindo a abordagem "Referências dos pais"
- Para encontrar descendentes, basta procurar os ancestrais, pois todos os descendentes devem conter os mesmos ancestrais
- Desvantagens :
- Precisa se preocupar em manter a matriz de ancestrais e o campo pai atualizados sempre que houver uma alteração nos relacionamentos, geralmente em vários documentos.
- Vantagens :
- Caminhos materializados :cada nó contém um caminho para si mesmo - requer regex
- Vantagens :
- Fácil de encontrar filhos e descendentes usando regex
- Pode usar um caminho para recuperar pai e ancestrais
- Flexibilidade, como encontrar nós por caminhos parciais
- Desvantagens :
- As alterações de relacionamento são difíceis, pois podem exigir alterações nos caminhos em vários documentos
- Vantagens :
- Conjuntos aninhados :Cada nó contém um campo "esquerdo" e "direito" para ajudar a encontrar subárvores
- Vantagens :
- Fácil de recuperar descendentes de maneira otimizada, pesquisando entre "esquerda" e "direita"
- Assim como a abordagem "Referência dos pais", é fácil encontrar pais e filhos
- Desvantagens :
- Precisa percorrer a estrutura para encontrar ancestrais
- As alterações de relacionamento têm o pior desempenho aqui do que qualquer outra opção, porque cada documento na árvore pode precisar ser alterado para garantir que "esquerda" e "direita" ainda façam sentido quando algo mudar na hierarquia
- Vantagens :
As cinco abordagens são discutidas em mais detalhes na documentação do MongoDB .
Sua segunda ideia combina as abordagens "Parent References" e "Child References" discutidas acima. Essa abordagem facilita a localização dos filhos e do pai e facilita a atualização de relacionamentos e os dados principais de um artigo (embora você precise atualizar os campos pai e filho), mas ainda precisa percorrê-lo encontrar ancestrais e descendentes.
Se você estiver interessado em encontrar ancestrais e descendentes (e se preocupa com isso mais do que poder atualizar facilmente os relacionamentos), considere adicionar uma matriz de ancestrais à sua segunda ideia para facilitar também a consulta de ancestrais e descendentes. Claro, atualizar relacionamentos se torna uma verdadeira dor se você fizer isso.
Conclusão:
-
Em última análise, tudo depende de quais ações são mais necessárias. Como você está trabalhando com artigos, cujos dados subjacentes (como o título) podem ser alterados com frequência, convém evitar a primeira ideia, pois seria necessário atualizar não apenas o documento principal desse artigo, mas todos os documentos filhos, bem como o pai.
-
Sua segunda ideia facilita a recuperação dos pais e filhos imediatos. Atualizar relacionamentos também não é muito difícil (é certamente melhor do que algumas das outras opções disponíveis).
-
Se você realmente deseja facilitar a localização de ancestrais e descendentes às custas de atualizar os relacionamentos com a mesma facilidade, opte por incluir uma matriz de referências de ancestrais.
-
Em geral, tente minimizar o número de travessias necessárias, pois elas exigem a execução de algum tipo de iteração ou recursão para obter os dados desejados. Se você valoriza a capacidade de atualizar relacionamentos, também deve escolher uma opção que altere menos nós na árvore (Referências Pai, Referências Filho e sua segunda ideia pode fazer isso).