MongoDB хранение деревьев

от автора

Есть несколько алгоритмов хранения деревьев в mysql, и мне кажется, что это в корне неправильно, так как реляционная база данных не предназначена для этого, а представление линейных структур данных в древовидную — один большой костыль в коде и понижение надёжности и скорости приложения. Как я задумался об использование NoSQL в частности mongoDB? Всё просто, меня на собеседование спросили:

Как построить дерево?

Я ответил:

Берём mongodb и документ с деревом из неё

Мне так и не перезвонили, но я не расстраиваюсь за то теперь я изучаю mongoDB и не люблю Mysql(к счастью или к сожалению я не знаю). В общем, разберём как всё это работает? На примере дерева комментариев написанном на php.

Сразу приведу код:

    // метод для подключения к mongodb находиться в абстрактном классе      // привожу его для понимания кода ниже     /**      * @return \MongoDB\Driver\Manager      * */     static function getConnect() {         if(!is_null(self::$_connect)) {             return self::$_connect;         }         self::$_connect = new \MongoDB\Driver\Manager(Config_Db::getConf()['mongodb']['connect']);         return self::$_connect;     }      // наш контроллер          /**      * add comment action      */     public function addCommentAction()     {         $time = time();         // массив с данными комментария         //insert new comment to the page         $arrData =  array(             'page' => $_POST['page_id'], // id страницы в mongo             'time' => $time, // время написания комментария             'name' => $_POST['name'], // имя написавшего             'comment' => $_POST['comment'] // сам комментрарий         );          $connect = Core_Model_Mongo::getConnect(); // подключение к монгодб          // две строки ниже подготовка к записи так как они не относятся к алгоритму          // то в дальнейшем я не буду на них заострять внимание         $write = new MongoDB\Driver\BulkWrite();          $writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY);           // и так, если человек отвечает на чей-то комментарий, то к нам приходит reply с id комментария          if(isset($_POST['reply']) && !empty($_POST['reply'])) {             // id комментария                    $reply = $_POST['reply'];             // путь для сохранения комментария             // другими словами, это путь по которому будет сохранен комментарий             $path = '';             if(isset($_POST['path']) && !empty($_POST['path'])) {                 $path = $_POST['path'];             } else {                 $path = 'replies';             }              // собственно, обновление данных по комментарию             $write->update(                 array('_id' => new MongoDB\BSON\ObjectID($reply)), // загружаем комментарий                  array('$push' => array($path => $arrData) ) // делаем push, в существующие данные, относительно path             );          } else {             $write->insert($arrData); // если комментарий новый вставляем в базу         }                  // запускаем запрос         $connect->executeBulkWrite(Config_Db::getConf()['mongodb']['db'] . '.comments', $write, $writeConcern);                  // и возвращаемся обратно          header('Location:' . $_POST['back_url']);     }     

И так в переменную path передаётся путь для сохранения, к примеру у нас в монго есть комментарий, представим его в виде ‘чистого’ массива, так как в реальности это массив объектов мы упростим всё до массива.

Массив с одним коментарием

   array (        'name' => 'test',        'comment' => 'test comment',    ); 

После update, с push и переменной path = ‘reply’, наш массив приобретёт вид:

Массив после push

   array (        'name' => 'test',        'comment' => 'test comment',        'reply' => array (               [0] =>                     array(                         'name' => 'test reply test'                        'comment' => 'test comment reply'                    )        )    ); 

А если отвечать на вложенный комментарий, то путь приобретёт вид ‘reply.0.reply’, то есть в reply комментария взять 0 элемент, и вставить туда новое поле reply с данными, после операции мы получим следующий массив.

Массив с репликой на вложеный комментарий

   array (        'name' => 'test',        'comment' => 'test comment',        'reply' => array (               [0] =>                     array(                         'name' => 'test reply test'                        'comment' => 'test comment reply'                        'reply' => array (                                   [0] =>                                          array(                                               'name' => 'test reply test'                                              'comment' => 'test comment reply'                                         )                                    )                              )                         )                   ); 

И это всё, весь алгоритм, просто вставить и потом просто взять этот массив для рендера таким какой он был, есть и будет. Рендер не буду расписывать так как рендер это не такая важная часть, да и я просто его делаю через print_r() шутка конечно, но принцип тот же… Спасибо за внимание дорогие хаброюзеры.

П.С.: В примере представлен алгоритм и в нём есть допущения, а именно отсутствие сортировки комментариев и её персистетности.

ссылка на оригинал статьи https://habrahabr.ru/post/279915/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *