【问题标题】:How do I efficiently limit query to the presence of an id in a many-to-many relationship in laravel?如何有效地将查询限制为 laravel 中多对多关系中是否存在 id?
【发布时间】:2018-06-25 07:30:49
【问题描述】:

场景:

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

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

有效,但由于有 7000 多条记录、7000 多条关系在数据透视表中定义,以及大约 30 个“类别”,搜索所需的时间比我离开它的时间要长。我未经证实的想法是,每条记录都在执行 where 查询,从而导致成百上千的查询。

我已经讨论过使用原始查询构建器来解决这个问题,只是传递具有该类别的记录 ID 列表,并使用简单的 where 在记录集合执行之前对其进行过滤,但这似乎违反直觉,导致我相信一定有更好的办法。

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

编辑 2018-01-16

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

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 的评论 - 使用 DB 外观构建原始查询,从中提取 id,然后在 whereIn 子句中使用它。

【问题讨论】:

  • 我不完全确定你的意思......如果你想要某个类别的记录,你不能只做$category->records吗?
  • 如果这就是我想要的,那就行了,是的。不幸的是,代码的编写方式是构建一个大型查询,我将进行编辑以澄清
  • 啊,对不起,现在我明白了。例如,您可以在数据透视表上运行查询以获取该类别的所有记录 ID,然后执行 $records->whereIn('id', $allOfThoseRecordIds)
  • 不错,我也想过,但我想知道是否有更好的方法。
  • 对于快速高效的搜索,您应该考虑创建一个非规范化的搜索表,或者使用由scout 支持的elasticsearch 等搜索服务。原始查询可能会有所帮助,但在达到不可优化的下限之前,您只能通过查询进行优化

标签: php laravel laravel-5 eloquent


【解决方案1】:

试试这个:

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

就是这样。祝你生活愉快!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 2021-08-29
    • 2019-02-07
    • 2018-11-22
    相关资源
    最近更新 更多