Структура реляционных таблиц представляет из себя простые списки. Комментарии должны храниться в базе данных в виде дерева: «родитель-наследники», что не реализовано в реляционной структуре. Существуют подходы в организации хранения деревьев в реляционных БД. В ходе решения задачи были рассмотрены подходы, плюсы и минусы которых опишу ниже.
Не совсем удобен для чтения — и это его основной недостаток. Чтение дерева большой вложенности - большая рекурсия. В дерево легко вносить изменения, менять местами и удалять узлы.
Вывод — данный алгоритм хорошо применим, если вы оперируете с небольшими древовидными структурами, которые часто поддаются изменениям.
С другой стороны, этот алгоритм также довольно уверенно себя чувствует и с большими деревьями, если считывать их порциями вида «знаю родителя — прочитать всех наследников». Хороший пример такого случая — динамически подгружаемые деревья. В этом случае алгоритм практически оптимизирован для такого поведения.
Однако он плохо применим, когда нужно вычитывать какие-либо иные куски дерева, находить пути, предыдущие и следующие узлы при обходе и вычитывать ветки дерева целиком (на всю глубину).
Очень хорош, когда требуется часто и много обращаться к иерархическим данным на чтение. Значительные трудности начинаются когда нам необходимо внести изменения в Nested Set дерево или удалить какую-либо из его ветвей. Для этого необходимо пересчитать все ключи той части дерева, которая находится справа от изменяемого узла, а также обновить информацию об уровнях вложенности. И все это не сделать одним простым запросом.
Вывод — Nested Set действительно хорош, когда нам необходимо считывать структуру деревьев из БД. При этом он одинаково хорош для деревьев любого объема.
Тем не менее, для иерархических структур, которые подвергаются частому изменению он, очевидно, не будет являться оптимальным выбором.
По сравнению с Nested Set, он более поддается изменениям. В то же время остается достаточно удобным для выборки деревьев целиком и их частей. Но, и он не идеален. Особенно по части поиска предков ветки. Использование именно этого алгоритма может быть заметно удобнее, для деревьев, над которыми часто выполняются как операции чтения, так и изменения. Удаление, добавление в конец или изменение узла — это операции довольно простые, и, как правило, не вызывают сложностей в данной модели.
Для нашей задачи необходмо как чтение дерева целиком, так и частая вставка. В связи с этим было решено выбрать подход - Materialized Path. Для устранения проблемы поиска предков скомбинируем данный подход с Adjacency List добавив поле parent_id.
Раньше не писал на Python 3.5 с Asyncio - решил попрбывать.
Также использовал aiohttp.
База данных - PosgreSQL 9.5 и расширение ltree с помошью которого и был реализован подход - Materialized Path.
Method | URL | Desc |
---|---|---|
GET | /comment/{comment_id} |
Выбока комментария |
PUT | /comment/{comment_id} |
Обновление комментария |
DELETE | /comment/{comment_id} |
Удаление комментрия, у которого нет дочерних |
POST | /comment/ |
Вставка комментария |
GET | /comment/history/{comment_id}/ |
Выборка истории комментрия |
GET | /comments/{user_id}/ |
Выборка комментариев пользователя |
Поля:
- user_id - id пользователя
- parent_id - id родительского комментария
- entity_type - тип сущности
- entity_id - id сущности
- text - текст комментария
Пока не валидирую entity_type, потому что не знаю какие могут быть значениея. Можно было просто добвить список типов, но пока отказался.
WEBSOCKET: /comment/ws/{entity_type}/{entity_id}/
Method | URL | Desc |
---|---|---|
GET | /tree/{comment_id}/ |
Получения дерева по id коментрия |
GET | /tree/{entity_type}/{entity_id}/ |
Получения дерева по сущности |
GET: /comments/{entity_type}/{entity_id}/?page={num}
Экспорт было решено разделить на два этапа:
- запрашивается создание выгрузки в файл, возвращается uuid заявки
- по uuid заявки проверяется состояние и в случае успеха возвращается файл
Method | URL | Desc |
---|---|---|
GET | /export/request/{user_id}/ |
создание заявки на экспорт по пользователю |
GET | /export/request/{entity_type}/{entity_id}/ |
создание заявки на экспорт по сущности |
GET | /export/file/{req_id}/ |
проверка состояния заявки(экспрота) |
./install.sh
Пока их мало.
pytest tests