【问题标题】:Laravel 4 - paginate with the filter Eloquent ORMLaravel 4 - 使用过滤器 Eloquent ORM 进行分页
【发布时间】:2013-06-06 15:30:25
【问题描述】:

我想用 2 个多对多关系过滤我的 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;

谢谢。

【问题讨论】:

    标签: orm filter laravel eloquent pagination


    【解决方案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()
    

    这是未经测试的,但应该按原样工作或稍作修改。

    享受吧!

    【讨论】:

    • 非常感谢,但是如何在 laravel 迁移中添加“添加索引”,这是不可能的?
    • 哎呀,我没看到,那个。谢谢
    【解决方案2】:

    你为什么不用两个简单的 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 个枢轴:区域和工作“candidate_region:id,candidate_id,region_id”和“candidate_job:id,candidate_id,job_id”
    • 看来你不能使用 where() 与急切加载的关系see source 但是同一个链接也向你展示了你如何在没有急切加载的情况下做到这一点(::with(... )) 并使用公共方法 join() 适当的数据透视表。如果您将您的地区和工作作为参数传递给该方法,并执行两次 INNER JOIN,您应该最终得到过滤后的数据。
    • 我不明白,对不起。我必须在我的 ORM 中包含 2 个 joins() ?
    【解决方案3】:

    这是在黑暗中拍摄的(我这里没有 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);
    

    【讨论】:

    • 谢谢,非常好,但是请求需要 13/20 秒,并且没有返回枢轴作业和区域
    • 您可以将您的 ->with(...) 添加回来并获取您的关系,但这只会增加查询时间,并从数据库中读取这些表两次。这就是我不喜欢模型和 Eloquent 的原因,用 Fluent 或纯 SQL 编写这个查询会更容易,运行起来也更快。
    • 谢谢,我正在尝试提出 Fluent 请求。它不起作用或请求需要 13 秒 DB::table('candidates') -&gt;join('candidates', function($join){ $join-&gt;on('candidates.id', '=', 'candidate_region.candidate_id'); }) -&gt;whereIn('candidates.region_id',$inputs['region']) -&gt;join('regions', function($join){ $join-&gt;on('regions.id', '=', 'candidate_region.region_id'); }) -&gt;whereIn('candidate_job.job_id',$inputs['job']) -&gt;where('imavailable', '1') -&gt;get();
    • 每张表有多少条记录?您将多少个区域 ID 和作业 ID 传递给您的两个 whereIn() ?
    • 我的表格包含:candidate_region = 8 068 总计; candidate_job = 6 735; candidate = 4 369;我通过$inputs['region'] : array(2,3,4,43,42) AND $inputs['region'] : array(1,2,5,8)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 2023-03-08
    • 2022-07-11
    • 2014-10-16
    • 2014-12-27
    • 2019-07-22
    相关资源
    最近更新 更多