ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

Nested Set library (aka MPTT, aka Hierarchy DB Trees)

October 01, 2008 2:58am

Subscribe [19]
  • #16 / Sep 07, 2010 7:13am

    creativeinsight

    5 posts

    I had just spent a week programming the nested sets in CI with out finding this, now i have i’d like to ask ifthunders code is based on every thing being encapsulated by a top node so every thing lies within the hierachy.

    I ask becouse i had been writting mine based on the top level being seperate nodes
    eg
    1-2
    3-6 parent to 4-5
    7-8

    where i belive this cod eis based on everything laying between
    eg
    1
    2-3
    4 7 parent to 5-6
    8-9
    10

    This is from reading through teh code i just want some one to confirm my conclusion who knows.

  • #17 / Sep 08, 2010 11:23am

    Jon L

    55 posts

    I don’t know if Thunder has updated his original code, but when I started making changes (for the code reflected in this thread), Thunder’s base script had assumed everything must exist within a single master node, to function.

    Such as:
    1{
    2-3
    4-5
    6{
    7-8
    }9
    }10


    My code made changes to make multiple master (or, root) nodes possible:
    1{
    2-3
    }4

    5{
    6{
    7-8
    }9
    }10


    All nodes, regardless, always occupy *at least* 2 spaces, such as 1-2, 3-4, 5-6, etc, as they always need a lft and rgt value (otherwise the system breaks down).


    Hope that answers your question.

  • #18 / Sep 08, 2010 11:28am

    creativeinsight

    5 posts

    thanks for that, i had got my head around the nested sets and had wrtitten my own upto the moving nodes as siblings functionality(yeah i’d done most the work)

    But i could not make out weather your code allwoed multiple top level nodes.
    i’m using the code in backendpro, did not find it in there till i found this thread.


    Thanks for the reply 😊

  • #19 / Sep 08, 2010 1:15pm

    WanWizard

    4475 posts

    I thought about a similar implementation, but decided against it.

    Instead, I have implemented multiple roots by introducing a tree_id, which is part of the WHERE clause in all queries. In parent tables, I only store the tree_id, all tree roots start with 1, and the queries never have to deal with records not part of the selected tree (so things like counting nodes is very strait forward).

  • #20 / Sep 08, 2010 4:53pm

    CroNiX

    4713 posts

    I’m a bit confused.  In Joe Celmo’s original article (linked to in the first post), there is a parent_id, left_id and right_id.  In this library, there is also an extra id, primary_key_column_name which it says would be the auto id column, which in Joe’s example is the parent_id.  Why is this extra ID necessary and what is it used for?  In this library, if primary_key_column is equivalent to Joe’s parent_key, what is the parent_column_name field used for? Why do you need more than just the parent_id, left_id and right_id?

    Maybe if someone could provide some simple sample sql table to test I could better understand how its working and the differences.  Please?  😊

    Thanks!

  • #21 / Sep 08, 2010 8:24pm

    WanWizard

    4475 posts

    What do you mean exactly by ‘this library’? The only one I can find is the one in the first post, and that doesn’t include a primary_key_column_name.

    The parent_id is needed when you’re using what is called the Modified Preorder Tree Traversal. So next to the left- and right pointers, you also have a direct link to the parent node in the tree. This can save some queries, depending on the implementation.

  • #22 / Sep 08, 2010 9:18pm

    CroNiX

    4713 posts

    From Nested_set.php

    public function setControlParams($table_name, $left_column_name = 'lft', $right_column_name = 'rgt', $primary_key_column_name = 'id', $parent_column_name = 'parent_id') {
            $this->table_name = $table_name;
            $this->left_column_name = $left_column_name;
            $this->right_column_name = $right_column_name;
            $this->primary_key_column_name = $primary_key_column_name;
            $this->parent_column_name = $parent_column_name;
        }
  • #23 / Sep 29, 2010 1:55pm

    CroNiX

    4713 posts

    I have a huge tree stored using the nested set storage method (primary id, left id, right id).  In addition, I also have a type_id which indicates what type of item each node is.  There is a certain type of node which can only be a child.

    What I am trying to do with a single query is retrieve all of these children (easy since they all have the same type) but then I also want the name of one (or more) of the parents that are of a certain type (category if you will).

    Think of a hierarchy of
    -Country (type_id = 0)
    —State (type_id = 1)
    —-City (type_id = 2)

    A city will always be a child node.  I am trying to get a list of cities, with their associated state name (there may be other cases where I need additional parents, such as the Country.  Basically, I want to retrieve the tree in “reverse order”.

    City, State
    City, State
    ...

    This is my modified “getTreePreorder” function (which returns node level and depth info in a single query too…useful if you are using code to build html from a tree)

    function getTreePreorder($node, $extra_cols = array(), $type = 6)
        {
            extract($this->_get_table_setup_data($node));
            $extra_select = $this->prep_cols('node', $extra_cols);
            
            $q = "SELECT node.`$pkcol`, node.`$leftcol`, node.`$rightcol`, $extra_select,
                    (COUNT(parent.`$leftcol`) - 1) AS depth,
                    CEIL((node.`$rightcol` - node.`$leftcol` - 1) / 2) AS child_quantity
                FROM
                    `$table` AS node,
                    `$table` AS parent
                WHERE node.`$leftcol` BETWEEN parent.`$leftcol` AND parent.`$rightcol`
                GROUP BY node.`$leftcol`
                HAVING node.`$leftcol` >= $leftval AND node.`$rightcol` <= $rightval
                ORDER BY node.`$leftcol`";
            $query = $this->db->query($q);
            
            $treeArray = array();
            
            foreach($query->result_array() AS $result)
            {            
                if($result['type_id'] <= $type)
                {
                    $treeArray[] = $result;
                }
            }
            
            return array(  "result_array"  => $treeArray,
                           "prev_left"     => $node[$leftcol],
                           "prev_right"    => $node[$rightcol],
                           "level"         => -2);
        }

    Here are 2 helper functions used above:

    //helper function gets the default column names and protects identifiers, as well as any optional column names provided in $extra_cols
        //$type can be 'node' or 'parent', depending on what is needed for the query
        function prep_cols($type = 'node', $extra_cols = array())
        {
            $cols = array();
            $extra_select = '';
            
            foreach($this->default_col_names as $d)
            {
                $cols[] = "$type.`$d`";
            }
            foreach($extra_cols as $d)
            {
                $cols[] = "$type.`$d`";
            }
            $extra_select = implode(', ', $cols);
               //if( ! empty($extra_select)) $extra_select = ', ' . $extra_select . ', ';
               
               return $extra_select;
        }
        
        //helper function to get the needed table and column info for various db queries.
        //returned array is meant to be extract()ed internally to use the variables in building SQL
        function _get_table_setup_data($node)
         {
             return array(
                 'table'      =>       $this->table_name,
                 'pkcol'         =>          $this->primary_key_column_name,
                'leftcol'    =>       $this->left_column_name,
                'rightcol'   =>       $this->right_column_name,
                  'pkval'         =>    (int) $node[$this->primary_key_column_name],
                'leftval'    => (int) $node[$this->left_column_name],
                'rightval'   => (int) $node[$this->right_column_name]
            );
         }

    And this is a piece of code that will retrieve the siblings of a given node.  This does what I need, but I need it incorporated into my original query or else this query will get executed several thousand times. (Also great for creating breadcrumbs).

    //retrieve ancestor nodes (branch) of the hierarchy for a supplied node, or a specific type of node from the branch.
        //if $hierarchy_type_id contains id of specific hierarchy type,
        //it will return only that node instead of the entire branch.
        //eg. enter the type id for state to find out what state a node is in.
        function get_branch($node, $hierarchy_type_id = '', $extra_cols = array())
        {
            extract($this->_get_table_setup_data($node));
            
            $extra_select = $this->prep_cols('parent', $extra_cols);
            
            $having = (empty($hierarchy_type_id)) ? '' : " HAVING parent.`type_id` = $hierarchy_type_id ";
            
            $q = "SELECT
                    $extra_select
                FROM
                    `$table` AS node,
                    `$table` AS parent
                WHERE
                    node.`$leftcol` BETWEEN parent.`$leftcol` AND parent.`$rightcol` AND
                    node.`$pkcol` = $pkval
                $having
                ORDER BY
                    parent.`$leftcol`";
            
            return $this->db->query($q)->result_array();
        }

    Any guidance would be greatly appreciated.  I’m not very good with these more complex queries.

  • #24 / Jan 08, 2011 4:49pm

    mrbinky3000

    33 posts

    Hello, just wondering if anyone has uploaded the most recent version of this wonderful library class to this thread.  I only found the one attached file on the first post of this thread.  Is that the most current version?

    Thanks in advance.

  • #25 / Feb 10, 2011 12:45am

    Strike

    1 posts

    Is thunder’s version most complete? there isn’t anything else thats complete, library or model class for nested sets.

    TIA.

  • #26 / Mar 08, 2011 6:24pm

    arlong

    2 posts

    in my controller(i added library on autoload):     
    $this->nested_set->setControlParams(‘nested_set_tree’); 
    $root_nodes1 = $this->nested_set->getRootNodes();
    i SEE this error “:
    Fatal error: Call to undefined method CI_DB_mysql_driver::getwhere() in C:\wamp\www\application\libraries\Nested_set.php on line 322”


    ANDDD
    how i can add a new data to database this system?

  • #27 / Mar 08, 2011 7:29pm

    WanWizard

    4475 posts

    Find another solution.

    Appearantly the nested sets post in the wiki is very dated, the getwhere() method was deprecated a long time ago, and is no longer present in CI 2.x.

    You could have a look at Datamapper, it includes a nested sets extension (http://datamapper.wanwizard.eu/pages/extensions/nestedsets.html) which is still in beta, but seems to work just fine…

  • #28 / May 09, 2012 9:15pm

    tinsn

    1 posts

    Anyone can upload the zip file of this library ?
    The download link in first page doesn’t work.

    BTW, switch it back to a model is a good idea.

  • #29 / May 10, 2012 11:11am

    Glazz

    170 posts

    Anyone can upload the zip file of this library ?
    The download link in first page doesn’t work.

    BTW, switch it back to a model is a good idea.

    You can use Zebra MPTT http://stefangabos.ro/php-libraries/zebra-mptt/ and adapt it to CodeIgniter, i have done it so i know it works, but i’m not using mptt anymore.

  • #30 / Dec 30, 2012 7:50pm

    extractortotem

    4 posts

    Hi,

    can somebody please paste in here a mysql schema for this library?
    thanks a lot!

    regards,
    ET

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases