Pull to refresh

Метод хранения материализованных путей в БД.

Reading time 2 min
Views 1.5K
Основным преимуществом данного метода является доступ к дочерним узлам любого уровня в один запрос к БД (правда с INNER JOIN).

Пример:
необходимо в разделе /company/ добраться до списка новостей (item1, item2)
  • /company/ О компании
    • /company/news/ Новости
      • /company/news/item2/ Вторая новость
      • /company/news/item1/ Первая новость новость

    • /company/history/ История
    • /company/contacts/ Контакты


Данные хранятся в таблицах со следующей структурой:
paths — дерево с путями
id
parent_id # хранится id родителя (paths.id)
name # имя узла, уникальное в пределах одного уровня
path # путь (/company/, /company/news/item1/)
title # для наглядности


path_have_childs — таблица ссылок, хранит список дочерних узлов с уровнями относительно родительского узла

parent_id # id родительского узла (paths.id)
child_id # id дочернего узла (paths.id)
level # уровень дочернего узла относительно родительского


Данные — таблица с путями:
id parent_id name path title
1   / Главная
2 1 company /company/ О компании
4 2 news /company/news/ Новости
5 4 item1 /company/news/item1/ Новость 1
6 4 item2 /company/news/item2/ Новость 2
3 1 catalogue /catalogue/ Каталог
7 3 category1 /catalogue/category1/ Категория 1
8 7 category2 /catalogue/category1/category2/ Категория 2


Дополнительная таблица — хранилище уровней дочернего узла относительно родительского:
parent_id child_id level
1 2 1
1 8 3
1 7 2
1 6 3
1 5 3
1 4 2
1 3 1
2 5 2
2 6 2
2 4 1
3 7 1
3 8 2
4 6 1
4 5 1
7 8 1

Запрос генерирующий дополнительную таблицу для уровней — для каждого узла находятся все дочерние узлы, даже те которые не являются непосредственно дочерними, и вычисляется уровень вложенности относительно текущего узла:
INSERT INTO path_have_childs
SELECT
    P.id AS parent_id,
    C.id AS child_id,
    (LENGTH(C.path) - LENGTH(REPLACE(C.path,'/','')))
- (LENGTH(P.path) - LENGTH(REPLACE(P.path,'/','')))
FROM paths AS P
    INNER JOIN paths AS C ON (C.path LIKE CONCAT(P.path, '_%'))


Выбор всех дочерних узлов узла X (parent_have_childs.parent_id) с уровнем Y (parent_have_childs.level):
SELECT C.path
FROM path_have_childs AS PHC
    INNER JOIN paths AS C ON (PHC.child_id = C.id)
WHERE
    PHC.level = Y
    AND PHC.parent_id = X


Конструктивные комментарии и критика приветствуются…
Tags:
Hubs:
0
Comments 36
Comments Comments 36

Articles