如何有效地限制查询在laravel中多对多关系中是否存在id?

时间:2018-01-16 14:44:02

标签: php laravel laravel-5 eloquent

情景:

我正在为一组给定的数据构建搜索系统。大多数情况是直截了当的 - 其中记录标题包含X,其中记录日期在Y 之前,等等。我遇到困难的地方基本上是类别搜索。每个记录属于零个或多个类别(存在关系数据透视表,每行包含一个记录和一个类别),当用户搜索类别A时,我想返回属于该类别的所有记录。我已经使用了WhereHas,但它似乎非常慢。在这个例子中,假设$ category是一个正确验证为类别的数字id,$ records是一个尚未被get,pagination,all等执行的雄辩查询构建器(我的函数检查是否有几个定义$ request->输入参数,然后根据指定参数的要求附加$ record的位置,仅在考虑所有参数后执行它:)

if(!empty($category)) {
 $records = $records->whereHas('categories', function($query) use ($category) 
  {
   $query->where('category_id', $category);
  });
}

有效,但由于有7000多条记录,数据透视中定义了7000多个关系,大约有30个“类别”,因此搜索所需的时间比我放弃的时间要长。我未经证实的想法是每个记录执行where查询,从而导致数百或数千个查询。

我已经讨论了使用原始查询构建器接近这个并且只是传递具有该类别的记录ID列表并使用简单的位置在执行之前过滤记录集合,但它似乎反直觉,导致我相信一定有更好的方法。

问题 如何有效地将$ records-> get()返回的记录限制为与$ category类别定义关系的记录。

修改2018-01-16

为了澄清,虽然我可以简单地执行$ category->记录来返回属于某个类别的所有记录,但这是更大的搜索引擎的一部分。代码的完整结构如下所示:

If($subject_search_term) {
   $records->where('subject', $subject_search_term)
}

If(some other search criteria is defined) {
   $records->where(someothercriteria);
}

If(Category search criteria is defined) {
   $records->whereHas(something);
}

$records->paginate(20);

此外,我需要查询这些多对多关系中的两个(除了'类别',假设还有一个独立于它的'主题',但结构和想法相似) 。据我所知,我需要根据记录构建查询并相应地过滤它。

编辑2

对于有这个问题的其他人来说,似乎更有效的方式(而且我发现的效率最高)是Joel Hinz的评论 - 使用数据库外观来构建原始查询,从中获取id,以及在whereIn子句中使用它。