Yii2 中的线程数据
Threaded data in Yii2
我正在通过 Active Record
寻找解决方案,以在单个查询中获取分层数据。
我现在做的是首先获取所有数据,然后使用递归函数将数组转换为所需的数组。
$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;
}
它工作正常。但最近我经历了CakePHP's find('threaded'),我认为它会节省递归函数执行时间和更少的代码。
我很好奇 Active Record 中是否也存在任何功能。
Yii2 中没有这样的功能。 CakePHP 还将在后台执行多个查询,并将其包装在 multi-threaded 调用中。如果您实际上只能执行一个查询,您将获得的主要 speed-advantage。
有两种方法可以实现:
- 您的方式...获取所有内容并将其合并到您的代码中
- 上面评论中提到的 NestedSet 模式
嵌套集
对于 Yii2,我们有一个非常好的扩展实现了嵌套集模式。你可以在这里找到它:
https://github.com/creocoder/yii2-nested-sets
优缺点
优点是 - 显然 - 您可以通过单个查询获取所有内容。您甚至可以将多棵树保存在一个 table.
中
主要缺点是按列排序,同时仍保持树结构。嵌套集由两个属性组织:左和右。这意味着,所有数据都根据这两个属性进行排序。要获取按名称排序的 tree-structure,您仍然必须实现 code-side 功能以在查询后更改接收到的 data-set。最干净的方法是在保存时对数据进行排序...意思是根据其在所需排序中的位置插入一条新记录
维基百科对嵌套集有很好的解释:
https://en.wikipedia.org/wiki/Nested_set_model
这张图展示了它是如何工作的:
示例:'slacks' 和 'jackets' 是 'suits' 的 children,因为它们的左右属性都在左 (3) 和右 (8) 之间'suits' 的值。如果你想添加一个 child 到 'jackets' 你会在 6 和 7 之间注入它......因此将所有高于或等于 7 的值增加 2。新注入的 'jackets' 的 child 将收到左值 7 和右值 8。
如您所见,您现在只需过滤左右属性即可轻松获取整个(子)树。如果您想要从 'suits' 向下的所有内容,您的查询将如下所示:
SELECT * FROM mytable WHERE left >= 3 AND right <= 8 ORDER BY left ASC
您问题的最终答案
如果你的主要关注点是舒适
没有。没有这样的功能。如果您仍然想要数据库中的常规树并且只是不想关心合并数据,则必须为 CakePHPs 方法编写类似的功能。这应该很容易,我想会有很多人对此感兴趣。
如果您最关心的是速度
使用嵌套集。这是一个非常棒的模式,非常强大!
这是另一种无需递归即可存储和获取树的方法。它需要 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;
这里是一组类 for yii2 to manage this ree
我正在通过 Active Record
寻找解决方案,以在单个查询中获取分层数据。
我现在做的是首先获取所有数据,然后使用递归函数将数组转换为所需的数组。
$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;
}
它工作正常。但最近我经历了CakePHP's find('threaded'),我认为它会节省递归函数执行时间和更少的代码。
我很好奇 Active Record 中是否也存在任何功能。
Yii2 中没有这样的功能。 CakePHP 还将在后台执行多个查询,并将其包装在 multi-threaded 调用中。如果您实际上只能执行一个查询,您将获得的主要 speed-advantage。
有两种方法可以实现:
- 您的方式...获取所有内容并将其合并到您的代码中
- 上面评论中提到的 NestedSet 模式
嵌套集
对于 Yii2,我们有一个非常好的扩展实现了嵌套集模式。你可以在这里找到它:
https://github.com/creocoder/yii2-nested-sets
优缺点
优点是 - 显然 - 您可以通过单个查询获取所有内容。您甚至可以将多棵树保存在一个 table.
中主要缺点是按列排序,同时仍保持树结构。嵌套集由两个属性组织:左和右。这意味着,所有数据都根据这两个属性进行排序。要获取按名称排序的 tree-structure,您仍然必须实现 code-side 功能以在查询后更改接收到的 data-set。最干净的方法是在保存时对数据进行排序...意思是根据其在所需排序中的位置插入一条新记录
维基百科对嵌套集有很好的解释: https://en.wikipedia.org/wiki/Nested_set_model
这张图展示了它是如何工作的:
示例:'slacks' 和 'jackets' 是 'suits' 的 children,因为它们的左右属性都在左 (3) 和右 (8) 之间'suits' 的值。如果你想添加一个 child 到 'jackets' 你会在 6 和 7 之间注入它......因此将所有高于或等于 7 的值增加 2。新注入的 'jackets' 的 child 将收到左值 7 和右值 8。
如您所见,您现在只需过滤左右属性即可轻松获取整个(子)树。如果您想要从 'suits' 向下的所有内容,您的查询将如下所示:
SELECT * FROM mytable WHERE left >= 3 AND right <= 8 ORDER BY left ASC
您问题的最终答案
如果你的主要关注点是舒适
没有。没有这样的功能。如果您仍然想要数据库中的常规树并且只是不想关心合并数据,则必须为 CakePHPs 方法编写类似的功能。这应该很容易,我想会有很多人对此感兴趣。
如果您最关心的是速度
使用嵌套集。这是一个非常棒的模式,非常强大!
这是另一种无需递归即可存储和获取树的方法。它需要 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;
这里是一组类 for yii2 to manage this ree