Reputation: 4392
We're currently building a website with a categorized MySQL table containing various competences, and we noticed that the nested set model would be optimized for this. Although, we've got a pretty serious problem - the nested set model doesn't allow any sorting, and we really need that possibility. I'd like the output data to be array(id, name, depth), as this function supports (though without any kind of sorting):
function tree()
{
$query = 'SELECT node.id, node.name, (COUNT(parent.name) - 1) AS depth FROM test_competence AS node, test_competence AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft';
$result = mysql_query($query) or die(mysql_error());
while($data = mysql_fetch_assoc($result))
{
$returnarray[] = $data;
}
return $returnarray;
}
I've started with a function but have no idea how to continue:
function tree_sorted()
{
//Get data
$query = 'SELECT node.id, node.name, node.parent, (COUNT(parent.name) - 1) AS depth FROM test_competence AS node, test_competence AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft';
$result = mysql_query($query) or die(mysql_error());
//Fetch gotten data
while($data = mysql_fetch_assoc($result))
{
$fetched[$data['depth']][$data['id']] = array($data['name'], $data['parent']);
}
//Sort fetched data
foreach($fetched as $i => $row)
{
asort($row);
$sorted[$i] = $row;
}
//Merge sorted data (???)
foreach($sorted as $i => $arr)
{
foreach($arr as $x => $row)
{
$returnarray[] = array('id' => key($row), 'name' => $row[0], 'depth' => $x);
}
}
Any help would be greatly appreciated. I've googled for different ways to sort data from nested sets, but without any good result.
Thank you in advance.
EDIT: Now I've tried some with the uasort() function which feels to be the right way, but the problem still remain.
Upvotes: 1
Views: 3137
Reputation: 36483
If you need sort a set of nodes in a tree, and maintain unlimited numbers of levels in the tree, might I recommend using pre-ordered tree traversal?
See http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ for an example implementation.
The point is that you maintain a left and right value for each node. You could also maintain a depth column for each node, which tells which level of the tree it is in. You can use these left and right values to sort nodes by their order in the tree, and use the depth value to only select a given number of levels of the tree.
The only notable downside of this approach is that you have to actively maintain those left and right values when altering the structure of the nodes.
Upvotes: 1
Reputation: 30555
Taking a stab in the dark, since nested set-tree data is, by definition, already sorted, it sounds like you need to convert the data into another format (usually a flat one) in order to sort it. The easiest way to achieve this is to simply work through the data, creating a flat dataset as you go.
You do already have a few options in the SQL. Ordering by the Left ID gets you in-order traversal, if I have the terminology correct. This is usually what people want when they list a set-tree as it makes sense when flattened into a list. I'd be experimenting with the ORDER BY
clause in the SQL; for example, ordering by the depth parameter would give you a level-order traversal. Try combining that with node.name
.
Upvotes: 0
Reputation: 6089
In my experience using the nested set model is not really necessary unless you expect some really heavy traffic. I'm not sure what exactly you need the hierarchy for, but I would recommend checking whether a simple parent-son-table with a cache in front of it wouldn't suffice, it's much easier to maintain and work with
Again, this of course depends on your application and how worried you are about performance issues.
Upvotes: 0