我想用多对多关系过滤我的ORM请求:区域和作业。
我需要分页,但$ final-> paginate()是不可能的,但我不知道,为什么。
如何改善我的代码使用 - > paginate()和没有Paginatore :: make
/* sélectionne tout les candidats qui sont disponnibles, et qui ont une date inférieure
* à celle configuré
*/
$contacts = Candidate::with('regions', 'jobs')
->where('imavailable', '1')
->where('dateDisponible', '<=', $inputs['availableDate'])
->get(); // ta requete pour avoir tes contacts, ou par exemple tu fais un tri normal sur tes regions. Il te reste à trier tes jobs.
// ajoute un filtre, pour n'afficher que ceux qui reponde true aux 2 test dans les foreachs
$final = $contacts->filter(function($contact) use($inputs) {
// par défaut ils sont false
$isJob = false;
$isRegion = false;
// test que le candidat à l'un des jobs recherché par l'entreprise
foreach($contact->jobs as $job) {
// si le job id du candidat est dans la liste, alors on retourne true
if(in_array($job->id, $inputs['job'])) {
$isJob = true;
}
}
// test que le candidat accepte de travailler dans l'une des régions echerchées
foreach($contact->regions as $region) {
// si region id du candidat est dans la liste, alors on retourne true
if(in_array($region->id, $inputs['region'])) {
$isRegion = true;
}
}
// si les 2 renvoie true, alors nous returnons le candidat à la vue
if($isRegion && $isJob){
return true;
}
else{
return false;
}
});
// converti le resultat en tableau pour l'importer dans le Paginator
$finalArray = $final->toArray();
// calcule le nombre de candidat dans le tableau
$finalCount = count($finalArray);
// créer le pagniate manuellement, car on ne peux faire $final->paginate(20)
$paginator = Paginator::make($finalArray, $finalCount, 2);
// return la liste des candidats
return $paginator;
感谢。
答案 0 :(得分:1)
好的,第三次是魅力:
首先,您的性能问题来自数据库结构,而不是查询。
您需要添加以下索引才能获得严重的性能提升:
ALTER TABLE `candidate_region` ADD INDEX `REGION_ID` ( `region_id` )
ALTER TABLE `candidate_region` ADD INDEX `CANDIDATE_ID` ( `candidate_id` )
ALTER TABLE `candidate_job` ADD INDEX `JOB_ID` ( `job_id` )
ALTER TABLE `candidate_job` ADD INDEX `CANDIDATE_ID` ( `candidate_id` )
使用适当索引的数据透视表可以更好地工作。
第二,这是您要运行的(纯)SQL查询:
SELECT *
FROM candidates
INNER JOIN candidate_region
ON candidates.id = candidate_region.candidate_id
INNER JOIN candidate_job
ON candidates.id = candidate_job.candidate_id
WHERE imavailable = 1 AND dateDisponible <= '2013-12-31' AND region_id IN (2,3,4,43,42) AND job_id IN (1,2,5,8)
使用上面的索引,此查询将在一秒钟内运行。没有索引,它会在我的机器上超时。
第三次,这就是此查询在Fluent中的样子:
DB::table('candidates')
->join('candidate_region', 'candidates.id', '=', 'candidate_region.candidate_id');
->join('candidate_job', 'candidates.id', '=', 'candidate_job.candidate_id');
->whereIn('candidate_region.region_id',$inputs['region'])
->whereIn('candidate_job.job_id',$inputs['job'])
->where('imavailable', '1')
->where('dateDisponible', '<=', $inputs['availableDate'])
->get(); // Or paginate()
这是未经测试的,但应该按原样或稍作修改。
享受!
答案 1 :(得分:0)
为什么不用两个简单的whereIn()?
替换你的filter()$contacts = Candidate::with('regions', 'jobs')
->where('imavailable', '1')
->where('dateDisponible', '<=', $inputs['availableDate'])
->whereIn('job_id', $inputs['job'])
->whereIn('region_id', $inputs['region'])
->get();
这样你就可以像你想的那样使用paginate()。
答案 2 :(得分:0)
这是一个在黑暗中拍摄的照片(我这里没有设置laravel)但是应该可以正常工作。
更改候选模型以添加新方法,该方法执行连接和过滤:
class Candidate extends Eloquent {
/* Le code existant de ton modèle "Candidate" est ici */
/* Nouvelle méthode qu'on ajoute au modèle pour le filtrer par region et job */
public static function forRegionsAndJobs($regions, $jobs)
{
return static::join(
'candidate_region',
'candidates.id', '=', 'candidate_region.candidate_id'
)->whereIn('region_id', $regions)
->join(
'candidate_job',
'candidates.id', '=', 'candidate_job.candidate_id'
)->where('job_id', $jobs);
}
}
然后,您可以使用过滤器调用该模型,并按照您希望的方式进行分页:
$contacts = Candidate::forRegionsAndJobs($inputs['region'], $inputs['job'])
->where('imavailable', '1')
->where('dateDisponible', '<=', $inputs['availableDate'])
->paginate(25);