用于递归结果的Laravel查询构建器?例如id,parent_id

tif*_*ang 6 php mysql recursion laravel-4

所以我的数据结构如下:

id|parent_id|name
1 |null     |foo
2 |1        |bar
3 |2        |baz
Run Code Online (Sandbox Code Playgroud)

所以基本上foo->bar->baz.我很难理解如何使用laravel的查询构建器来获取子行的行,然后是它的祖先(直到parent_id == null).这可以用laravel完成吗?我已经完成了一些研究,Postgres RECURSIVE虽然MySQL没有(Postgres递归查询在遍历parent_id时更新字段的值).

我相信MySQL有类似的东西:如何在MySQL中进行递归SELECT查询?

但是我如何在Laravel中实现这个呢?

我的开始代码基本上是使用查询范围,但我只是没有做到正确:

Model::select('name')->getParent(3); //get baz and the ancestors of baz
protected function scopeGetParent($id) {
  $parent = Model::where('id', '=', $id);
  return $query->getParent($parent->parent_id);
}
Run Code Online (Sandbox Code Playgroud)

我想要的结果是:

name
baz
bar
foo
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

tif*_*ang 8

所以在摆弄merge()Collections类的方法之后:

public static function ancestors($id)
{
    $ancestors = Model::where('id', '=', $id)->get();

    while ($ancestors->last()->parent_id !== null)
    {
      $parent = Model::where('id', '=', $ancestors->last()->parent_id)->get();
      $ancestors = $ancestors->merge($parent);
    }

    return $ancestors;
}
Run Code Online (Sandbox Code Playgroud)

这将产生我需要的东西,但我相信它可以更清洁,所以请随意编辑它!


ruu*_*ter 5

我修改了tiffanyhwang解决方案,并将其转变为非静态方法,并包含一个属性访问器,以使其更易于获得结果。

public function ancestors()
{
    $ancestors = $this->where('id', '=', $this->parent_id)->get();

    while ($ancestors->last() && $ancestors->last()->parent_id !== null)
    {
        $parent = $this->where('id', '=', $ancestors->last()->parent_id)->get();
        $ancestors = $ancestors->merge($parent);
    }

    return $ancestors;
}
Run Code Online (Sandbox Code Playgroud)

和访问器,从模型属性中检索祖先的集合

public function getAncestorsAttribute()
{
    return $this->ancestors();
    // or like this, if you want it the other way around
    // return $this->ancestors()->reverse();
}
Run Code Online (Sandbox Code Playgroud)

所以现在您可以得到像这样的祖先:

$ancestors = $model->ancestors;
Run Code Online (Sandbox Code Playgroud)

并且由于它是一个Collection,因此您现在可以轻松地执行以下操作:

echo $model->ancestors->implode('title',', ');
Run Code Online (Sandbox Code Playgroud)


小智 4

另一种方法是使用etrepat/baum包,它是Nested set model的 Laravel 实现。它使用更快的有序树并使用非递归查询。虽然您的数据结构如下:

root
  |_ Child 1
    |_ Child 1.1
    |_ Child 1.2
  |_ Child 2
    |_ Child 2.1
    |_ Child 2.2
Run Code Online (Sandbox Code Playgroud)

嵌套集合模型的结构如下:

 ___________________________________________________________________
|  Root                                                             |
|    ____________________________    ____________________________   |
|   |  Child 1                  |   |  Child 2                  |   |
|   |   __________   _________  |   |   __________   _________  |   |
|   |  |  C 1.1  |  |  C 1.2 |  |   |  |  C 2.1  |  |  C 2.2 |  |   |
1   2  3_________4  5________6  7   8  9_________10 11_______12 13  14
|   |___________________________|   |___________________________|   |
|___________________________________________________________________|
Run Code Online (Sandbox Code Playgroud)

插入节点很简单:

$child1 = $root->children()->create(['name' => 'Child 1']);
Run Code Online (Sandbox Code Playgroud)

  • 虽然这是一个很棒的包,但它本身就说:缺点是插入/移动/删除需要复杂的 SQL。读取速度很快,但改变结构却很慢...... (2认同)