Part of the EllisLab Network
   
2 of 7
2
Hierarchical database trees using nested sets
Posted: 05 March 2007 09:59 AM   [ Ignore ]   [ # 16 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  647
Joined  09-30-2006

Thanks joeles, but that won’t work methinks because in nested sets we’re not tracking the parentid to establish a relationship. The relationship is maintained by the lft and rgt column values. I suppose a column could be added to the table that tracks the parentid when a child is inserted, but that would also require modification of the deletion and (sub) tree moving and deletion methods as entries may become orphaned otherwise.

The goal is to compute the parent from the lft and rgt comparison. In esras model, there is a getAncestor() function - which should actually be called getAncestry() - which returns the path to a given childnode in a tree (not the parent as stated in the docs). I’m trying to get a modification of that to only return the immediate parent.

Building on top of that method, you can get the ancestry (path to a node) by comparing parent.lft < node.lft AND parent.right > node.right.

Now there is a way to compute the depth of nodes in a tree. It’s not in the class, but I’m using the code as shown on the mysql.com article. The solution to my problem will likely be in a combination of the ancestry AND where parent.depth = node.depth -1. That should do the trick.

I’ve just not been able to successfully wrap it into a SQL query.

 Signature 

sitesquad.net | < insert catchy tagline here />

Profile
 
 
Posted: 05 March 2007 10:17 AM   [ Ignore ]   [ # 17 ]  
Summer Student
Total Posts:  11
Joined  12-12-2006

really
wooww
i think it’ can’t be
because it’s still in one table

i have try but i can find good one
something like this

SELECT k.Kategori_id as id,
k.Kategori_name as subparent,
k.Kategori_name as parent
from kategori k where k
.Leftid < (
Select Leftid from kategori where 1
) and k.Rightid >
(
Select Rightid from kategori where 1
)
ORDER BY k.Rightid ASC

but i don’t have any idea,if someone have please tell us

Profile
 
 
Posted: 05 March 2007 10:29 AM   [ Ignore ]   [ # 18 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  486
Joined  09-14-2006

::Removing foot from mouth::

Mirage, I can’t believe I totally glazed over something so fundamental. Duh! Thanks for the quick schooling. I’ll study up more before offering up additional suggestions. smile

 Signature 

Code Igniter 1.5.4 / CentOS 5 / PHP 5.2.3 / Apache 2.2.2 / MySQL 5.0.27

Profile
 
 
Posted: 05 March 2007 01:07 PM   [ Ignore ]   [ # 19 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  647
Joined  09-30-2006

joeles - you’re being too hard on yourself. grin

 Signature 

sitesquad.net | < insert catchy tagline here />

Profile
 
 
Posted: 05 March 2007 03:05 PM   [ Ignore ]   [ # 20 ]  
Grad Student
Avatar
Rank
Total Posts:  55
Joined  08-23-2006
mirage - 05 March 2007 12:52 AM

Using the example - is there a single SELECT that can be written to return the name of a node in one and the name of it’s parent in a second column? So that the output would look like this:

+-----------------+--------------+
|
name            | parent_name  |
+-----------------+--------------+
|
top             |              |
|
movies          | top          |
|
romantic comedy | movies       |
|
westerns        | movies       |
|
books           | top          |
| ...             | ...          |
+-----------------+--------------+

I seem to think it’s possible, but it appears I’m experiencing sql-jam..

Thank you!
Juergen

 

Took me a while to figure it out, but this ought to do it:

 

SELECT      cat.name      AS name,
            
parent.name   AS parent
FROM        categories    
AS cat

                 LEFT JOIN categories
AS parent
                 ON parent
.leftval = (

                           
SELECT           MAX(rel.leftval)
                           
FROM             categories AS rel
                           WHERE            rel
.leftval < cat.leftval AND rel.rightval > cat.rightval
         
                  
)

ORDER BY cat.leftval ASC

It means selecting on the same table with three aliases (cat, parent and rel) at the same time but hey…  smile

 Signature 

Senior Developer, MyBuilder.com

Hierarchical data trees using nested sets

Profile
 
 
Posted: 05 March 2007 03:12 PM   [ Ignore ]   [ # 21 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  647
Joined  09-30-2006

Awesome thunder!

I just arrived at the same conclusion using a subquery, but I won’t post it because yours is leaner and cleaner. Nice job!

Many thanks,
Juergen

 Signature 

sitesquad.net | < insert catchy tagline here />

Profile
 
 
Posted: 05 March 2007 03:18 PM   [ Ignore ]   [ # 22 ]  
Summer Student
Total Posts:  11
Joined  12-12-2006
thunder - 05 March 2007 03:05 PM
mirage - 05 March 2007 12:52 AM

Using the example - is there a single SELECT that can be written to return the name of a node in one and the name of it’s parent in a second column? So that the output would look like this:

+-----------------+--------------+
|
name            | parent_name  |
+-----------------+--------------+
|
top             |              |
|
movies          | top          |
|
romantic comedy | movies       |
|
westerns        | movies       |
|
books           | top          |
| ...             | ...          |
+-----------------+--------------+

I seem to think it’s possible, but it appears I’m experiencing sql-jam..

Thank you!
Juergen

 

Took me a while to figure it out, but this ought to do it:

 

SELECT      cat.name      AS name,
            
parent.name   AS parent
FROM        categories    
AS cat

                 LEFT JOIN categories
AS parent
                 ON parent
.leftval = (

                           
SELECT           MAX(rel.leftval)
                           
FROM             categories AS rel
                           WHERE            rel
.leftval < cat.leftval AND rel.rightval > cat.rightval
         
                  
)

ORDER BY cat.leftval ASC

It means selecting on the same table with three aliases (cat, parent and rel) at the same time but hey…  smile

 

wowwwwwww
thanks dud you the best

Profile
 
 
Posted: 05 March 2007 03:49 PM   [ Ignore ]   [ # 23 ]  
Grad Student
Avatar
Rank
Total Posts:  55
Joined  08-23-2006
mirage - 05 March 2007 09:59 AM

The goal is to compute the parent from the lft and rgt comparison. In esras model, there is a getAncestor() function - which should actually be called getAncestry() - which returns the path to a given childnode in a tree (not the parent as stated in the docs). I’m trying to get a modification of that to only return the immediate parent.

Are you sure? the getAncestor method should only return the immediate parent. Admittedly, a getAncestry method would be a handy addition too (and reasonably straight-forward to add, I think)

Now there is a way to compute the depth of nodes in a tree. It’s not in the class, but I’m using the code as shown on the mysql.com article. The solution to my problem will likely be in a combination of the ancestry AND where parent.depth = node.depth -1. That should do the trick.

I’ve just not been able to successfully wrap it into a SQL query.

That mysql.com article has some useful stuff in it - I’ll see if I can add some of those queries/sections into an updated class for the wiki. A getTree with parent_id, parent_name and depth/level would be very handy! smile

 Signature 

Senior Developer, MyBuilder.com

Hierarchical data trees using nested sets

Profile
 
 
Posted: 05 March 2007 03:50 PM   [ Ignore ]   [ # 24 ]  
Grad Student
Avatar
Rank
Total Posts:  55
Joined  08-23-2006
mirage - 05 March 2007 03:12 PM

Awesome esra!

I just arrived at the same conclusion using a subquery, but I won’t post it because yours is leaner anc cleaner. Nice job!

Many thanks,
Juergen

smile

But my name’s not esra! wink

 Signature 

Senior Developer, MyBuilder.com

Hierarchical data trees using nested sets

Profile
 
 
Posted: 05 March 2007 04:00 PM   [ Ignore ]   [ # 25 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  647
Joined  09-30-2006

Sorry about that. Edited.

 Signature 

sitesquad.net | < insert catchy tagline here />

Profile
 
 
Posted: 05 March 2007 04:01 PM   [ Ignore ]   [ # 26 ]  
Grad Student
Avatar
Rank
Total Posts:  55
Joined  08-23-2006
Jameson - 16 February 2007 05:48 AM

Unfortunately it won’t work under PHP4.

Call to a member function on a non-object in [...]/nested_sets_model.php on line 294

Specifically, this function causes error:

$query = $this->db->query($sql);

Ahh, that may be because your database library isn’t loaded at the point you’re making the query (me, I tend to have the database ‘autoloaded’ as I tend to use database driven sessions and site configs).

If you add $this->load->library(‘database’ ); to the constructor of the Category_demo controller, it should be ok.

That said, PHP4 users do still need to go through the Nested_sets_model class and remove all the “public” and “private” modifiers to the function names

so…

public function Nested_sets_model()

Needs to become

function Nested_sets_model()

And likewise with the private ones too. :S

I’ll change that for the next version I upload.

 Signature 

Senior Developer, MyBuilder.com

Hierarchical data trees using nested sets

Profile
 
 
Posted: 06 March 2007 12:11 AM   [ Ignore ]   [ # 27 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  647
Joined  09-30-2006
thunder - 05 March 2007 03:49 PM
mirage - 05 March 2007 09:59 AM

... there is a getAncestor() function - which should actually be called getAncestry() - which returns the path to a given childnode in a tree (not the parent as stated in the docs). I’m trying to get a modification of that to only return the immediate parent.

Are you sure? the getAncestor method should only return the immediate parent. Admittedly, a getAncestry method would be a handy addition too (and reasonably straight-forward to add, I think)

Yes thunder, positive. The getAncestor function is missing the MAX clause you used in that nifty subquery. grin

That mysql.com article has some useful stuff in it - I’ll see if I can add some of those queries/sections into an updated class for the wiki. A getTree with parent_id, parent_name and depth/level would be very handy! smile

Actually I think you got most of it covered - and then some. The biggest problem with all of the articles written about ‘nested sets’ is that they all focus on querying the tree and have only poor examples of adding data. But you have solved that rather nicely in your model.

 Signature 

sitesquad.net | < insert catchy tagline here />

Profile
 
 
Posted: 10 March 2007 07:21 PM   [ Ignore ]   [ # 28 ]  
Lab Technician
Avatar
RankRankRankRank
Total Posts:  1749
Joined  06-23-2006

Is the wiki broken since the website upgrade? I can view the wiki entry, but the model file download isn’t working.

 Signature 

Mac OS X 10.4.10, Apache 1.3.3, PHP 5.2.3, CodeIgniter 1.5.x., baby!

Profile
 
 
Posted: 14 March 2007 02:34 PM   [ Ignore ]   [ # 29 ]  
Grad Student
Avatar
Rank
Total Posts:  55
Joined  08-23-2006

Wiki downloads appear to be working again ok

smile

 Signature 

Senior Developer, MyBuilder.com

Hierarchical data trees using nested sets

Profile
 
 
Posted: 21 March 2007 01:14 PM   [ Ignore ]   [ # 30 ]  
Lab Technician
Avatar
RankRankRankRank
Total Posts:  1163
Joined  08-06-2006

I’m curious about this class and I put on my thinking cap to try to understand what all the fuss is about.  gulp Everyone keeps talking about trees and heirarchical data but I couldn’t really get at why the data in trees couldn’t be represented in a properly normalized database.

I think I’ve come up with a short answer for myself to what kind of data you would want to store in this type of database:

1) you don’t know the structure of the data before you start to get it (e.g., ad hoc categories, tags)
2) you do know the structure of the dataset but the data is not nice and tidy - it is heterogenous. For instance, you might want to store data with attributes that exist for data in one part of the dataset that don’t exist in another part and, for that problem, database normalization techniques won’t help to bring order. (e.g, a personnel database where some departments have more levels of heirarchy than others)

I suppose this is why thunder included the categories demo data because it nicely demonstrates a dataset that is not a good candidate for your typical database normalization.

If I am wrong or this definition needs refinement, please chime in!

EDIT: I found this writeup that has some clear discussion of why to use nested sets.

 Signature 

imap_pop get email | site_migrate port sites | OOCalendar | PhotoBox2 gallery | CI/EE 2 word_limiter, yep, wrote it

Profile
 
 
   
2 of 7
2
 
Post Marker Legend
New Topic New posts Hot Topic Hot Topic with new posts New Poll New Poll Moved Topic Moved Topic Sticky Topic Sticky topic
Old Topic No new posts Hot Old Topic Hot Topic with no new posts Old Poll Old Poll Closed Topic Closed Topic Announcement Announcements
Theme
Change Theme
Visitor Statistics
The most visitors ever was 819, on March 11, 2010 11:15 AM
Total Registered Members: 120603 Total Logged-in Users: 39
Total Topics: 126642 Total Anonymous Users: 2
Total Replies: 665701 Total Guests: 481
Total Posts: 792343    
Members ( View Memberlist )
Newest Members:  bell143paololukDarleneChadbourneRashadSargIvar89HonschowmtRetliffherzigerjudith