Laravel递归-查找“;最后一篇文章”;


Laravel recursion - finding the "last post"

我有一个论坛系统,有很多类别,有很多线程,有很多帖子。

因此,在给定的论坛上,我应该能够找出特定论坛的最后一个帖子。一个论坛可以有许多子论坛(又称儿童论坛)。我只能做其中的一部分。

表格演示:

| id | parent_id | name              | is_category |
|----|-----------|-------------------|-------------|
| 1  | 0         | Suggestions       | 1           |
| 2  | 1         | site suggestions  | 0           |
| 3  | 1         | forum suggestions | 0           |
| 4  | 2         | bugs              | 0           |

这是我的代码:

public function lastPost()
{
    foreach ($this->threads()->orderBy('updated_at')->get() as $thread) {
        $post = $thread->lastPost();
    }
    if ($this->hasSubforum()) {
        foreach ($this->subforums as $subforum) {
            $post = $subforum->lastPost();
        }
    }
    return $post;
}

正如您所看到的,lastPost()被调用,直到论坛不再有子论坛。我收到了一个子论坛中最新帖子的最后一篇。到目前为止还不错。然而,最后一篇帖子将是子论坛的顺序。因此,如果最后一篇文章在倒数第二个子论坛中,它将返回最后一个子论坛的最后一篇,因为最后一个论坛在递归中是最后返回的。

我该怎么解决这个问题?

谢谢!

我认为应该对这个问题采取不同的方法。当你有相当多的用户时,你尝试的方法会使你的数据库崩溃。如果你知道这个树有多深,那么做很多这样的"左联接"对性能更好:

select  d3.parent_id as parent3_id,
        d2.parent_id as parent2_id,
        d1.parent_id as parent_id,
        d1.id as product_id,
        d1.name
from      demo d1
left join demo d2 on d2.id = d1.parent_id 
left join demo d3 on d3.id = d2.parent_id 
... join as many as you think it will have data ...
where  $this->id in (d1.parent_id, 
               d2.parent_id, 
               d3.parent_id) 
order by 1, 2, 3;

在这种情况下,您将只执行1个查询,在您的情况下,将执行n+1个查询,如果使用延迟加载,则执行更多查询。

另一种方法是创建一个"路径"列,如"1/15/19/27/34",它将指示所有父ID。

您还可以创建一个"last_post"表,该表将指示每个类别的最后一篇文章是什么。这也会提高你的表现。

这篇文章有很多信息:如何创建MySQL层次递归查询

更改递归函数以接受post参数并比较日期。

public function lastPost($post = null)
{
    foreach ($this->threads()->orderBy('updated_at')->get() as $thread) {
        $cur_post = $thread->lastPost();
        if ($post === null) {
            $post = $cur_post;
        }
        else {
            $cur_post_date = new DateTime($cur_post->date_added); // Or whatever you use to get last post date
            $post_date = new DateTime($post->date_added);
            if ($cur_post_date > $post_date) {
                $post = $cur_post;
            }
        }  
    }
    unset($cur_post, $cur_post_date, $post_date);
    if ($this->hasSubforum()) {
        foreach ($this->subforums as $subforum) {
            $post = $subforum->lastPost($post);
        }
    }
    return $post;
}

然而,正如Felippe Duarte所说,递归查询数据库是一件坏事,所以如果你要在生产中使用论坛,请寻找替代方案。