0

ORM リクエストを、多対多の 2 つの関係 (地域とジョブ) でフィルタリングしたいと考えています。

paginate が必要ですが、$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;

ありがとう。

4

3 に答える 3

1

さて、3回目は魅力です:

まず、パフォーマンスの問題は、クエリではなくデータベース構造に起因します。

パフォーマンスを大幅に向上させるには、次のインデックスを追加する必要があります。

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)

上記のインデックスを使用すると、このクエリは 1 秒未満で実行されます。インデックスがないと、私のマシンでタイムアウトしました。

3 番目に、このクエリは 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()

これはテストされていませんが、そのままで、またはわずかな変更で動作するはずです。

楽しみ !

于 2013-06-07T15:55:12.380 に答える
0

これは暗闇の中でのショットです (ここでは laravel のセットアップはありません) が、ほとんどそのままで動作するはずです。

Candidate モデルを変更して、結合とフィルタリングを行う新しいメソッドを追加します。

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);
于 2013-06-06T18:43:35.407 に答える
0

filter() を単純な 2 つの whereIn() に置き換えてみませんか?

$contacts = Candidate::with('regions', 'jobs')
                        ->where('imavailable', '1')
                        ->where('dateDisponible', '<=', $inputs['availableDate'])
                        ->whereIn('job_id', $inputs['job'])
                        ->whereIn('region_id', $inputs['region'])
                        ->get();

そうすれば、希望どおりに paginate() を使用できるはずです。

于 2013-06-06T16:13:41.683 に答える