You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel多态与多对多关联:收藏帖子查询及方法优化问询

解决方案

1. 特定收藏夹已收藏帖子的高效查询(支持分页与按收藏时间排序)

在Collection模型中新增以下方法,通过表连接直接关联Post模型,无需加载多余的Bookmark数据,同时支持基于bookmark_collection.created_at的排序和分页:

class Collection {
    // 现有关联方法...

    public function bookmarkedPosts() {
        return Post::query()
            ->join('bookmarks', function ($join) {
                $join->on('posts.id', '=', 'bookmarks.bookmarkable_id')
                     ->where('bookmarks.bookmarkable_type', Post::class);
            })
            ->join('bookmark_collection', function ($join) {
                $join->on('bookmarks.id', '=', 'bookmark_collection.bookmark_id')
                     ->where('bookmark_collection.collection_id', $this->id);
            })
            ->select('posts.*', 'bookmark_collection.created_at as added_to_collection_at')
            ->orderBy('bookmark_collection.created_at', 'desc');
    }
}

使用示例:

// 分页获取收藏夹内的帖子,按加入时间倒序排列
$posts = $collection->bookmarkedPosts()->paginate(15);

该方案直接查询Post表,通过连接关联中间表和书签表,既避免了无用模型的加载,又能直接利用bookmark_collection的时间字段完成排序和分页,完全匹配需求。


2. User模型bookmarkedPosts方法优化

原方法的子查询排序可以简化,同时改用表连接提升性能,以下是两种优化方案:

方案一:表连接简化查询(推荐)

class User {
    public function bookmarkedPosts() {
        return Post::query()
            ->join('bookmarks', function ($join) {
                $join->on('posts.id', '=', 'bookmarks.bookmarkable_id')
                     ->where('bookmarks.bookmarkable_type', Post::class)
                     ->where('bookmarks.user_id', $this->id);
            })
            ->select('posts.*', 'bookmarks.created_at as bookmarked_at')
            ->orderBy('bookmarks.created_at', 'desc');
    }
}

方案二:利用Eloquent关联链(适合需要保留关联特性的场景)

如果需要保留Eloquent关联的便利性(如加载其他关联模型),可以通过用户的bookmarks关联筛选出帖子:

class User {
    public function bookmarks() {
        return $this->hasMany(Bookmark::class);
    }

    public function bookmarkedPosts() {
        return $this->bookmarks()
            ->where('bookmarkable_type', Post::class)
            ->with('bookmarkable')
            ->orderBy('created_at', 'desc')
            ->get()
            ->pluck('bookmarkable');
    }
}

优化说明:

  • 原方法的嵌套子查询排序可替换为直接使用bookmarks.created_at(符合单用户单帖子仅一条书签的业务逻辑),减少查询复杂度。
  • 表连接方案的性能优于hasManyThrough,尤其是数据量较大时,查询效率更高。
  • 新增的bookmarked_at/added_to_collection_at字段可直接用于前端展示收藏时间,无需额外处理。

内容的提问来源于stack exchange,提问作者grazdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:47:06