【问题标题】:Search based on many to many relation with multiple condition on same column基于具有多个条件的多对多关系在同一列上进行搜索
【发布时间】:2016-12-22 13:02:49
【问题描述】:

我的 laravel 5.3 项目有一个多对多关系。 有两个模型与此问题相关联。它们是JobTag。 模型 Job 可以有很多 Tag 与之关联,模型 Tag 也可以关联很多 Job。 我在两个模型类中使用关键字“belongsToMany”分配了关系Many To Many。 关系的数据库是: 表:工作

________________
 id |  title    |
____|___________|
  1 |  Developer|
____|___________|
  2 |  Designer |
____|___________|
  3 |  Tester   |
____|___________|
  4 |  manager  |
____|___________|

表格:标签

_________________
 id |  tag_name |
____|___________|
  1 |  php      |
____|___________|
  2 |  html     |
____|___________|
  3 |  css      |
____|___________|

数据透视表job_tag

_____________________
 job_id |  tag_id   |
________|___________|
  1     |   1       |
________|___________|
  1     |   2       |
________|___________|
  2     |   1       |
________|___________|
  3     |   1       |
________|___________|
  3     |   2       |
________|___________|
  4     |   2       |
________|___________|

用户可以传递多个标签名称来检索与用户传递的两个标签相关的作业。(AND条件)

示例:当用户传递 tag_name “php”和“html”时,我想显示工作 [id:1 title:developer] 和 [id:2 title:designer] 的详细信息].

提示 : 检索同时带有“php”和“html”标签的作业记录

注意:用户传递的标签名称的数量没有定义,即用户可以传递尽可能多的。


这是我尝试过的:

$jobs = Job::whereHas('tags', function ($query) use($params) {
                    foreach ($params['tags'] as $tag) {
                        $query->where('tag', $tag);
                    }
                });

上面的代码没有返回任何东西,而是生成了下面的sql:

select * from `jobs` where exists (select * from `tags` inner join `job_tag` on `tags`.`id` = `job_tag`.`tag_id` where `job_tag`.`job_id` = `jobs`.`id` and (`tag` = css) and (`tag` = javascript))

我试图根据这个sql得到结果,结果不行。

希望你们理解我的问题并帮助我找到解决方案。 提前致谢。

【问题讨论】:

    标签: php mysql laravel eloquent laravel-5.3


    【解决方案1】:

    一种选择是使用多个whereHas

    $query = Job::query();
    
    foreach ($params['tags'] as $tag) {
        $query->whereHas('tags', function ($q) use($tag) {
            $q->where('tag', $tag);
        });
    }
    
    $jobs = $query->get();
    

    假设您有一个标签数组 id 为:

    $tag_ids = [2, 4];
    

    那你可以试试:

    Job::whereHas('tags', function($q) use($tag_ids) {
            $q->whereIn('tag_id', $tag_ids)
              ->groupBy('job_id')
              ->havingRaw('COUNT(DISTINCT tag_id) = '.count($tag_ids));
        })->get();
    

    【讨论】:

    • 第一个选项效果很好。它会生成这样的查询:- select * from 'jobs' where exists (select * from 'tags' inner join 'job_tag' on 'tags'.'id' = 'job_tag'.'tag_id' where 'job_tag'.'job_id' = 'jobs'.'id' and 'tag' = "php") and exists (select * from 'tags' inner join 'job_tag' on 'tags'.'id' = 'job_tag'.'tag_id' where 'job_tag'.'job_id' = 'jobs'.'id' and 'tag' = "html")._Thank You_
    【解决方案2】:

    在您的 foreach 中,您需要将标签与 OR 进行比较,而不是 AND

    $jobs = Job::whereHas('tags', function ($query) use ($params) {
        $query->where(function ($query2) use ($params) {
            foreach ($params['tags'] as $tag) {
                $query->orWhere('tag', $tag);
            }
        })
    });
    

    我不确定是否需要第二级关闭,但如果您最终在查询中添加任何其他 WHERE 条件,这将有所帮助。

    【讨论】:

    • 代码生成错误:unexpected '}',如果删除$query->where(function ($query2) use ($params) {,则列出所有“工作”而不是与标签相关的搜索。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 2014-07-24
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    相关资源
    最近更新 更多