Hello everyone) I use Laravel, MariaDB.
For example, we have a table like this, let's say categories.
id | name | _lft | _rgt | parent_id | path | is_folder |
---|---|---|---|---|---|---|
1373 | Windows | 1 | 10 | NULL | 1373 | 1 |
1374 | Glass unit | 2 | 7 | 1373 | 1373.1374 | 1 |
1375 | Accessories | 8 | 9 | 1373 | 1373.1375 | 1 |
1376 | Installation | 3 | 4 | 1374 | 1373.1374.1376 | 0 |
1377 | Adjustment | 5 | 6 | 1374 | 1373.1374.1377 | 0 |
The Categories model uses the Kalnoy\Nestedset\NodeTrait trait. In the code below, the query builder already contains basic filters (for example, by name)
if (!empty($filters['recursiveSearch']) && CommonService::parseBoolean($filters['recursiveSearch']) === true) {
/** @var QueryBuilder $query */
}
When passing the recursiveSearch parameter, it is necessary to output not only the values that match the filter, but also all their parents.
For example: by the filter name=adjust we get the string Adjustment. with recursiveSearch you also need to get Windows and Glass unit.
The query can also have a filter parentId. If parentId=null&name=adjust&recursiveSearch=true
then it should return Windows
Please help :)
Initially I thought to do just with('ancestors')
, but the result gets into the relations, and should be in the main query.
Then I made an additional query, got the result of the first selection, got pluck('ancestors')
and already substituted their IDs into the resulting query. It worked, but if in the initial selection there are, for example, 1000 records and each has 3 parents, then in the end there will be where on 3000 IDs.
As an idea, without consider Laravel, you can do this without recursion, since you have the full path for each row.
id | name | _lft | _rgt | parent_id | path | is_folder |
---|---|---|---|---|---|---|
1373 | Windows 1 | 10 | null | 1373 | 1 | |
1374 | Glass unit | 2 | 7 | 1373 | 1373.1374 | 1 |
1375 | Accessories | 8 | 9 | 1373 | 1373.1375 | 1 |
1376 | Installation | 3 | 4 | 1374 | 1373.1374.1376 | 0 |
1377 | Adjustment | 5 | 6 | 1374 | 1373.1374.1377 | 0 |
select p.*
from categories c
inner join categories p on
find_in_set(cast(p.id as char),replace(c.path,'.',','))>0
where c.id=1377
id | name | _lft | _rgt | parent_id | path | is_folder |
---|---|---|---|---|---|---|
1373 | Windows 1 | 10 | null | 1373 | 1 | |
1374 | Glass unit | 2 | 7 | 1373 | 1373.1374 | 1 |
1377 | Adjustment | 5 | 6 | 1374 | 1373.1374.1377 | 0 |
Simpler do this by 2 queries
select path from categories where id=1377
Output is '1373.1374.1377'.
2.Query all parents with parameter '1373,1374,1377'
select *
from categories
where find_in_set(cast(id as char),'1373,1374,1377')>0
Request for id and all childrens
select *
from categories c
where find_in_set(cast(1374 as char),replace(c.path,'.',','))>0
id | name | _lft | _rgt | parent_id | path | is_folder |
---|---|---|---|---|---|---|
1374 | Glass unit | 2 | 7 | 1373 | 1373.1374 | 1 |
1376 | Installation | 3 | 4 | 1374 | 1373.1374.1376 | 0 |
1377 | Adjustment | 5 | 6 | 1374 | 1373.1374.1377 | 0 |