2015-09-04 56 views
5

我正在通过Active Record寻找解决方案来获取单个查询中的分层数据。Yii2中的螺纹数据

我现在正在做的是首先获取所有数据,然后将数组转换为具有递归函数的所需数组。

$allUsers = User::find() 
     ->asArray() 
     ->all(); 
$arr = Yii::$app->TreeComponent->getUserChildren($allUsers, $userId, $userId); 

和TreeComponent

public function getUserChildren($src_arr, $currentId, $userId, $parentFound = false) 
{ 
    $cats = array(); 
    foreach ($src_arr as $row) { 
     if ($row['id'] == $userId) { 
      $row['parent'] = ""; 
     } 
     if ((!$parentFound && $row['id'] == $currentId) || $row['parent'] == $currentId) { 
      $rowData = array(); 
      foreach ($row as $k => $v) 
       $rowData[$k] = $v; 
      $cats[] = $rowData; 
      if ($row['parent'] == $currentId) { 
       $cats = array_merge($cats, $this->fetchRecursive($src_arr, $row['id'], true)); 
      } 
     } 
    } 
    return $cats; 
} 

其工作的罚款。但最近我通过CakePHPfind('threaded'),我认为它会节省递归函数的执行时间和更少的代码。

我很好奇Active Record是否还有其他功能。

+2

没有这方面的功能,但你可能想使用[嵌套列表](https://github.com/creocoder/yii2-nested-sets)。 – Beowulfenator

+1

Yii的AR无法在单次调用中填充分层数据。 您可以使用引用来构建像数组结构的树,以避免递归。如果你有兴趣,我可以发表一个例子。 – nineinchnick

+0

@nineinchnick是的请我想看看这个例子。 – ankitr

回答

2

在Yii2中没有这样的功能。 CakePHP也将在后台执行多个查询,并将其包装在多线程调用中。如果您实际上只能执行一项查询,您将获得主要的速度优势。

有两种方法来实现这一目标:

  • 你的方式...获取的一切,你的代码中进行合并
  • NestedSet模式在评论中提到上述

NestedSet

对于Yii2,我们有一个非常好的扩展实现嵌套设置模式。你可以在这里找到它:

https://github.com/creocoder/yii2-nested-sets

优点和缺点

的优点是 - 很明显 - 您可以取得与单个查询一切。你甚至可以在一个表中保存多个树。

主要缺点是按列排序,同时仍保持树结构。嵌套集合具有两个属性:左侧和右侧。这意味着,所有数据都根据这两个属性进行排序。要获取按名称排序的树结构,您仍然必须实现代码方功能,以在查询后更改接收的数据集。最彻底的方法是对数据进行排序,同时节省...这意味着根据其在您需要的排序

维基百科有嵌套组的一个非常好的地方explenation插入新记录: https://en.wikipedia.org/wiki/Nested_set_model

该图显示它是如何工作的:

NestedSet illustration

例如:“松弛”和“夹克”是“套装”既是其左和右的属性的儿童是左(3)和“右(8)值之间西装'。如果你想添加一个孩子到'夹克',你会注入它之间的6和7 ...因此增加所有值高于或等于7两个。然后新注入的'夹克'的孩子将得到左侧值7和右侧值8。如您所见,您现在可以通过简单地过滤左侧和右侧属性来轻松获取整个(子)树。我F你想要的一切,从“套装”向下您的查询会是这个样子:

SELECT * FROM mytable WHERE left >= 3 AND right <= 8 ORDER BY left ASC 

最后回答你的问题

如果你的主要焦点是舒适

号没有这样的功能。如果你仍然想在你的数据库中使用一个普通的树,并且不想关心合并数据,那么你必须为CakePHP方法编写一个similliar功能。这应该很容易,我认为会有很多人对此感兴趣。

如果您主要关注的是速度

使用嵌套组。这是一个模式的地狱,太强大了!

+0

感谢您的答复@ PLM57。我主要关心的是速度,因为有成千上万的记录。而在我的情况下,可以有多于2个节点的子节点,如果嵌套集合仍然有效的方法? – ankitr

+0

不客气!是的,您可以根据需要为每个节点添加尽可能多的孩子!它不像一棵只允许两个孩子的二叉树......它是一棵常规树,但组织方式不同(带有左/右属性而不是父母ID)。这篇wiki文章中的插图很好地解释了这一点:https://en.wikipedia.org/wiki/Nested_set_model#/media/File:NestedSetModel.svg – PLM57

0

这里是另一种存储树并获取它的方式,没有递归。它需要2个表格。

tree_data 

    Column | Type |           
-----------+---------+ 
id  | integer | 
parent_id | integer | 
level  | integer | 
sort  | integer | 


tree_structure 

Column | Type |       
--------+---------+ 
parent | integer | 
child | integer | 

实施例:

select * from tree_data; 

id | parent_id | level | sort 
----+-----------+-------+------ 
    1 |   0 |  0 | 1000 
    2 |   1 |  1 | 1000 
    3 |   1 |  1 | 2000 
    4 |   1 |  1 | 1500 
    5 |   1 |  1 | 1750 
    6 |   5 |  2 | 1000 


select * from tree_structure order by parent, child; 

parent | child 
--------+------- 
     1 |  1 
     1 |  2 
     1 |  3 
     1 |  4 
     1 |  5 
     1 |  6 
     2 |  2 
     3 |  3 
     4 |  4 
     5 |  5 
     5 |  6 
     6 |  6 

所得树:

├── 1 
│ ├── 2 
│ ├── 4 
│ ├── 5 
│  ├── 6 
│ ├── 3 

要查询树:

SELECT tree_data.* 
FROM tree_data 
INNER JOIN tree_structure ON tree_data.id = tree_structure.child and tree_structure.parent = 1 
ORDER BY level, sort; 

下面是一组类为yii2 to manage this ree