首页 > 解决方案 > 使用 spatie/laravel-query-builder 和 teamtnt/laravel-scout-tntsearch-driver

问题描述

我尝试将laravel tntsearchspatie query builder一起使用。基于 Spatie Query Builder 文档,我尝试按照以下方式构建我的查询

        if($request->has('kw')) {
           $keyword = response()->json($request->get('kw'));
           $query = Job::search($keyword);
        } else {
            $query = new Job();
        }

        $result = QueryBuilder::for($query)
               ->paginate()
               ->query();

由于 laravel tnt 搜索没有返回一个雄辩的对象,这个查询将失败。有没有办法将这两个包结合起来一起工作?

标签: laravelsearcheloquentfuzzy-search

解决方案


我完全按照您尝试使用 TNTSearch 驱动程序执行的操作,我得出了一个艰难的结论,即 Scout 根本不支持默认 QueryBuilder 对象所做的广泛的查询处理。这是设计使然。如果您阅读 Scout 文档,就会清楚地表明您必须先执行搜索,然后才能应用所有通常会使用的过滤器/排序查询。所以,这样想:搜索 > 过滤和排序搜索结果。

话虽如此,可能实现您想要的。它只需要 2 个查询而不是 1 个。也许有一天Scout会得到更好的支持。

我是这样做的:

设置一个变量来保存您的搜索结果 ID

$searchIds = blank($request->kw) ? [] : Job::search($this->search)->keys();

searchIds现在要么是一个空数组,要么是一个模型 ID 数组。现在您可以利用 Spatie 的 QueryBuilder 对象来应用您的过滤器和排序。

QueryBuilder::for(Job::class)
->allowedFilters([
    // your filters go here
])
->allowedSorts([
    // your sorts go here
])
->tap(function ($query) use ($searchIds) {
    return empty($searchIds) ? $query :  $query->whereIn('id', $searchIds);
})
->paginate();

在上面的示例中,我们使用该tap方法有条件地链接whereIn查询构建器方法。这是一种更聪明的方式,可以将查询编写得更简洁一些,但它相当于 write QueryBuilder::for(Job::class)->whereIn('id', $searchIds)。当没有搜索时,它将简单地省略该whereIn方法。

这会将您的 QueryBuilder 限制为仅与您的搜索匹配的结果,并且您可以将所有排序和过滤器应用于这些结果。


推荐阅读