我有一个论坛系统,有很多类别,有很多线程,有很多帖子。
因此,在给定的论坛上,我应该能够找出特定论坛的最后一个帖子。一个论坛可以有许多子论坛(又称儿童论坛)。我只能做其中的一部分。
表格演示:
| 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所说,递归查询数据库是一件坏事,所以如果你要在生产中使用论坛,请寻找替代方案。