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

Laravel 9集成MeiliSearch调用pagination()分页结果截断问题

问题根因

你的判断完全准确:

  1. query() 回调的执行时机是搜索引擎已经完成检索、返回分页结果之后,此时再用whereHas/whereDoesntHave做过滤,是在搜索引擎返回的固定数量结果里做二次筛选,自然会出现每页条数不足、提前翻到空页的问题——本质是分页计算在过滤之前就做完了。
  2. 你尝试传闭包给Scout的where()方法报500错误,是因为Scout的where()和Eloquent的where()逻辑完全不通用:它仅支持「字段名=匹配值」的简单键值对过滤,不接受闭包、关联查询这类关系型数据库才支持的语法,这和你查到的文档说明一致,搜索引擎本身没有表关联的概念,没法直接解析跨表的关联判断逻辑。

可行解决方案

方案1:冗余关联状态到搜索索引(推荐,性能最好,符合Scout+MeiliSearch设计逻辑)

搜索引擎的核心设计思路就是提前把过滤、搜索需要的字段都存在索引里,避免查询时做跨表计算,你只需要把「是否有销售记录」的状态提前同步到MeiliSearch的索引中即可:

  1. 修改Article模型的toSearchableArray()方法,新增冗余的过滤字段:
    public function toSearchableArray()
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => $this->content,
            // 新增冗余字段:标记当前文章是否存在销售记录
            'has_sold' => $this->sales()->exists(),
            // 其余需要纳入搜索/排序的字段按实际需求补充
        ];
    }
    
  2. 执行命令重新全量导入索引,让新增字段生效:
    php artisan scout:import "App\Models\Article"
    
  3. 搜索时直接用Scout原生where做过滤,不要用query()回调做结果筛选:
    $searchQuery = Article::search($this->meiliSearchText);
    
    match($this->showSold) {
        "true" => $searchQuery->where('has_sold', true),
        "false" => $searchQuery->where('has_sold', false),
        default => null
    };
    
    $paginateResult = $searchQuery->paginate($this->pagination);
    
    注意事项:当sales表的数据发生新增、删除时,要同步触发关联Article模型的索引更新,避免冗余字段和实际数据不一致。可以在Sale模型的模型事件中,调用对应文章的searchable()方法更新索引即可。

方案2:主键中转查询(适合小数据量场景,无需修改索引结构)

如果不想维护冗余字段、且匹配搜索关键词的总数据量不大(万级以内),可以先从搜索引擎取出所有匹配结果的主键,再交给Eloquent做关联过滤和分页:

// 先从MeiliSearch取出所有匹配关键词的文章ID
$matchArticleIds = Article::search($this->meiliSearchText)->keys();

// 用ID集合做SQL查询,所有关联过滤、分页逻辑走Eloquent原生逻辑
$paginateResult = Article::whereIn('id', $matchArticleIds)
    ->when($this->showSold === "true", fn($q) => $q->whereHas('sales'))
    ->when($this->showSold === "false", fn($q) => $q->whereDoesntHave('sales'))
    ->paginate($this->pagination);

注意事项:如果匹配关键词的结果超过10万条,一次性取出所有ID会带来较高的内存占用和接口延迟,大数据量场景优先选择方案1。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:45:59