【问题标题】:Efficient MySQL/Eloquent query to filter posts by more than 1 tag高效的 MySQL/Eloquent 查询,以超过 1 个标签过滤帖子
【发布时间】:2018-06-25 04:17:27
【问题描述】:

该设置由两个表(线程、标签)和一个数据透视表(tag_thread)组成,以允许多对多关系:一个线程可以有多个标签,一个标签可以用于多个线程。

表格的属性:

treads: id, title

tags: id, name

threads: id, thread_id, tag_id

现在我想使用多个标签而不是一个标签来过滤线程。所以我想获取与所有给定标签关联的所有线程?只使用一个,我可以通过 Laravel Eloquent 使用以下模型轻松完成:

$filteredThreads = $tag->threads()->get()

我已经设法用两个标签来做到这一点,但我觉得这是一种非常肮脏和低效的方法(特别是考虑到它会遍历整个 id 列表进行比较):

$threadIds = Thread::select('th.id')
        ->from('threads AS th')
        ->join('tag_thread AS tt', 'tt.thread_id', 'th.id')
        ->join('tags AS ta', 'tt.tag_id', 'ta.id')
        ->where('ta.name', $tag)
        ->pluck('id')
        ->toArray();

return $filteredThreads->whereIn('threads.id', $threadIds);

你能想出更好的解决方案吗?谢谢!

【问题讨论】:

  • JOIN tags AS ta ... JOIN tags AS tb ...

标签: mysql laravel eloquent many-to-many pivot-table


【解决方案1】:

如果您想获取具有标记的线程,该标记具有在$tagsNames 数组中定义的名称之一:

$tagsNames = ['popular', 'cool'];
Thread::whereHas('tags', function($q) use($tagsNames) {
    $q->whereIn('name', $tagsNames);
})->get();

【讨论】:

  • 非常好,非常感谢!如果我想获得所有标签都带有$tagsNames 名称的线程怎么办?缩小范围。
  • @Hillcow 在这种情况下,您需要在 whereHas() 闭包内使用 foreach($tagsNames as $name) { $q->where('name', $name); }
  • @Alexej 不幸的是,您的代码不起作用。它适用于 1 个标签,但不适用于 2 个标签。我认为问题是在第一个 where() 之后只剩下这个名称。使用另一个名称再次使用 where() 会产生 0 个结果。还有其他想法吗?
  • @Hillcow 我认为您在谈论第二条评论中的代码,因为答案中的代码有效。如果您询问foreach 之一,请尝试使用$q = $q->where('name', $name); 而不是$q->where('name', $name);
  • @Hillcow 看起来不错。你确定结果不对?您是否尝试在不使用foreach 的情况下对$q->where('name', 'tag1')->where('name', 'tag2'); 等两个标签进行硬编码?如果不起作用,请使用 foreach 循环创建多个 ->whereHas() 闭包,其中只有一个标签。
猜你喜欢
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多