Laravel join关联论坛多表查询获取最新内容异常求解
原代码用join拼接三张表的方案本质是把结构化的关联数据拍平成了二维表结果,天然存在三个硬伤:一是同名字段会互相覆盖(比如三张表都有id、created_at字段),二是一个线程对应N条帖子时会返回N行重复线程数据,加distinct也没法把帖子数据嵌套归集到对应线程下,三是没有配置排序规则自然拿不到按时间排序的最新内容。
Laravel下用Eloquent原生关联做这个需求逻辑更清晰,查询性能也更优,实现步骤如下:
第一步:先配置三个模型的关联关系
先把三个模块的模型关联补全,这是后续所有关联查询的基础:
- 分类(Category)模型关联下属线程
// Category模型内 public function threads() { return $this->hasMany(Thread::class, 'category_id', 'id'); }
- 线程(Thread)模型分别关联所属分类、下属所有帖子、下属最新帖子
// Thread模型内 // 关联所属分类 public function category() { return $this->belongsTo(Category::class, 'category_id', 'id'); } // 关联线程下所有帖子 public function posts() { return $this->hasMany(Post::class, 'thread_id', 'id'); } // 关联线程下最新发布的一条帖子,用于排序判断 public function latestPost() { return $this->hasOne(Post::class, 'thread_id', 'id')->latestOfMany('created_at'); }
- 帖子(Post)模型关联所属线程
// Post模型内 public function thread() { return $this->belongsTo(Thread::class, 'thread_id', 'id'); }
第二步:编写符合需求的查询逻辑
直接在Category模型中编写查询方法即可,不需要手动写join拼接:
// Category模型内,获取当前分类下按最新动态排序的线程及对应帖子 public function getLatestOrderedThreadsWithPosts() { return $this->threads() // 预加载所有关联帖子,避免N+1查询问题 ->with('posts') // 预加载最新帖子,方便前端直接展示最新回复 ->with('latestPost') // 排序规则:优先按线程下最新帖子的发布时间倒序,没有帖子的空线程按线程本身发布时间倒序 ->orderByDesc( \DB::raw('COALESCE((SELECT created_at FROM forum_posts WHERE forum_posts.thread_id = forum_threads.id ORDER BY created_at DESC LIMIT 1), forum_threads.created_at)') ) ->get(); }
返回结果说明
调用上述方法后,返回的是按最新动态从新到旧排序的线程集合:
- 每个线程模型实例下自动挂载
posts属性,值为该线程下所有帖子的集合,不需要手动做数据归集 - 每个线程额外挂载
latestPost属性,值为该线程下最新发布的帖子实例,可直接用于列表页展示最新回复信息 - 排序逻辑完全覆盖需求:刚发布的新线程、刚有新回复的老线程都会自动排在列表最前面
内容的提问来源于stack exchange,提问作者HOHOOH
相关产品推荐
相关产品推荐

