Modelo de conjunto aninhado: a melhor abordagem para lidar com dados hierárquicos

Quando você está trabalhando em um aplicativo Ruby and Rails, às vezes você precisa gerenciar um modelo / tabela que representa dados hierárquicos (também conhecido como árvore), como categorias de produtos, pastas, etc.

A abordagem mais fácil e comum para lidar com esse cenário consiste em implementar o Adjacency List Model, no qual cada registro da tabela (nó) tem uma referência ao seu pai.

Cenário

Além disso, temos uma gema muito utilizada para nos ajudar: atuar como árvore.

No entanto, essa abordagem tem grandes desvantagens em algumas situações, especialmente quando você deseja consultar todos os descendentes de um nó específico. A única forma de consegui-lo é percorrendo recursivamente seus filhos, fazendo uma consulta para cada filho em cada nível.

Por exemplo: Obter uma representação da árvore completa usando atuar como joia da árvore:

def get_tree(node)
node.children.each do |child|
puts child.name
get_tree(child)
end
end

get_tree(Category.root)

Isso é extremamente ineficiente, especialmente em árvores grandes, pois cada chamada de “node.children” faz uma consulta ao banco de dados.

Talvez você possa implementar um código mais eficiente usando SQL diretamente (assumindo o risco de incompatibilidades se o projeto for migrado para outro SGBD no futuro), mas o número de consultas sempre será dependente do tamanho da árvore.

Há uma exceção: usar uma consulta recursiva. No entanto, o DBMS relacional de código aberto mais usado no mundo, o MySQL, carece de suporte a consultas recursivas.

Modelo de conjunto aninhado para o resgate

É aqui que o modelo de conjunto aninhado pode nos ajudar. É outra abordagem para representar dados em forma de árvore que eliminam o problema mostrado acima.

Para entender a diferença entre Adjacency List e Nested Set, recomendo que você visite a explicação de Mike Hillyer .

Cenário

Resumindo, cada registro da tabela (nó) possui dois campos extras que nos permitem saber e extrair toda a sua árvore filha em apenas uma consulta. Espetacular!

As desvantagens: como você pode ver no link de Mike Hillyer, pode ser um pouco doloroso manter a árvore bem formada nas inserções ou remoções.

Mas é aqui que a magia das gemas de rubi vem para nos salvar. Com a incrível joia de conjunto aninhado, você pode abstrair da manutenção da árvore e aproveitar a melhoria na eficiência que nos traz o Modelo de conjunto aninhado.

O exemplo acima reescrito com gem de conjunto aninhado é tão simples quanto a seguir:

Category.root.descendants

Uau! Código mais simples e uma incrível melhoria de desempenho. São necessárias apenas duas consultas: uma para obter a raiz da categoria e uma (e apenas uma) para obter o resto da árvore. Não importa o quão grande possa ser!

Fontes: