基于多对多关系与同一列上的多个条件进行搜索
Search based on many to many relation with multiple condition on same column
我的 laravel 5.3 项目有一个 多对多关系 。
有两个模型与此问题相关。它们是 Job 和 Tag。
模型 Job 可以有很多 Tag 与之相关,模型 Tag 也可以有很多 工作。
我在两个模型 类 中使用关键字“belongsToMany”分配了关系 Many To Many。
关系的数据库是:
table:工作
________________
id | title |
____|___________|
1 | Developer|
____|___________|
2 | Designer |
____|___________|
3 | Tester |
____|___________|
4 | manager |
____|___________|
table : 标签
_________________
id | tag_name |
____|___________|
1 | php |
____|___________|
2 | html |
____|___________|
3 | css |
____|___________|
和枢轴table: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"[=15标签的工作记录=]
注意:用户传递的标签名称数量没有定义,用户可以传递多少就传递多少。
这是我试过的东西:
$jobs = Job::whereHas('tags', function ($query) use($params) {
foreach ($params['tags'] as $tag) {
$query->where('tag', $tag);
}
});
上面的代码 returns 除了生成以下内容 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 获取结果,但没有用。
希望你们理解我的问题并帮助我找到解决方案。
提前致谢。
在您的 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
条件,这将有所帮助。
一种选择是使用多个 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();
我的 laravel 5.3 项目有一个 多对多关系 。 有两个模型与此问题相关。它们是 Job 和 Tag。 模型 Job 可以有很多 Tag 与之相关,模型 Tag 也可以有很多 工作。 我在两个模型 类 中使用关键字“belongsToMany”分配了关系 Many To Many。 关系的数据库是: table:工作
________________
id | title |
____|___________|
1 | Developer|
____|___________|
2 | Designer |
____|___________|
3 | Tester |
____|___________|
4 | manager |
____|___________|
table : 标签
_________________
id | tag_name |
____|___________|
1 | php |
____|___________|
2 | html |
____|___________|
3 | css |
____|___________|
和枢轴table: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"[=15标签的工作记录=]
注意:用户传递的标签名称数量没有定义,用户可以传递多少就传递多少。
这是我试过的东西:
$jobs = Job::whereHas('tags', function ($query) use($params) {
foreach ($params['tags'] as $tag) {
$query->where('tag', $tag);
}
});
上面的代码 returns 除了生成以下内容 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 获取结果,但没有用。
希望你们理解我的问题并帮助我找到解决方案。 提前致谢。
在您的 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
条件,这将有所帮助。
一种选择是使用多个 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();