Search code examples
phpmysqllaravelnested-sets

How to efficiently insert an array as nested set model with Laravel/PHP and MySQL


I am using this package to handle hierarchy data in Laravel: https://github.com/lazychaser/laravel-nestedset

Their is an implemented functionality which provides the opportunity to create new data with a multidimensional array. So I have the following sample array (of a file/directory hierarchy):

array:3 [
  "name" => "Folder1"
  "type" => "folder"
  "children" => array:2 [
    0 => array:2 [
      "name" => "test1.txt"
      "type" => "txt"
    ]
    1 => array:3 [
      "name" => "Folder1.1"
      "type" => "folder"
      "children" => array:2 [
        0 => array:2 [
          "name" => "file.png"
          "type" => "png"
        ]
        1 => array:3 [
          "name" => "folder1.1.1"
          "type" => "folder"
          "children" => array:1 [
            0 => array:2 [
              "name" => "file.txt"
              "type" => "txt"
            ]
          ]
        ]
      ]
    ]
  ]
]

But their are directories with more than 10GB of data which means they have a much higher complexity than the shown example with a deep hierarchy. The database is already filled with over a million rows. And if I try to insert a new array the MySQL immediately runs on 100% CPU and needs about 20 minutes to insert that new structure into the database.

The reason is because it needs to calculate LEFT and RIGHT for nested set considering already existent data in the table.

Is there a more efficient way to insert such hierarchies into the database?


Solution

  • Quick example of adding the left and right items to the various arrays (assuming that the lowest level of the arrays is a row of items, so no need add a left and right to these individual items).

    Something like this could be used to add the values

    <?php 
    
      function array_left_right (&$array, &$counter = 1)
      {
        if (is_array($array))
        {
          $array['left'] = $counter++;
          foreach($array as $array_key=>&$array_item)
          {
                array_left_right($array_item, $counter);
          }
          $array['right'] = $counter++;
        }
      }
    
      $fred = array(array(array('a', 'b'), array('c', 'd'), array('e', 'f'), array('g', 'h')),array(array('aa', 'ab'), array('ac', 'ad'), array('ae', 'af'), array('ag', 'ah')));
    
      array_left_right($fred);
    
      print_r($fred);