2010-08-18 67 views
1

我一直忙于CakePHP框架几个月,现在我真的很喜欢它。目前我正在开发一个非常新的项目,并且完成了它应该的工作(我认为...),但是我对我写的一些代码感到不舒服。实际上,我应该优化分页条件查询,以便立即得到正确的结果(现在我通过一组Set :: extract方法调用来操作结果集。我有一个模型'网站'谁有一个与模型'SiteMeta'有很多关系。最后一张表看起来如下:id,site_id,key,value,创建。在cakePHP 1.3中找到hasMany关系的复杂查询查询1.3

在这最后一个模型中,我记录了几个值我想要存储的密钥的名称(例如alexarank,google pagerank,...),并且也是值。在给定的时间间隔,我让我的应用程序更新这个数据库,以便我可以跟踪这个值。

现在我的问题是这样的。

在各个网站(controller => Sites,action => index)的概述页面上,我想显示该网站的CURRENT网页排名。因此,我需要一个确切的SiteMeta记录,其中'created'字段最高,'key'中的值应该与'pagerank'字相匹配。我已经尝试了几个我在网上阅读的东西,但没有得到任何工作(包含,绑定模型等)。可能我做错了什么。

现在我得到这样的结果,当我做了$这个 - >分页

Array 
(
    [0] => Array 
     (
      [Site] => Array 
       (
        [id] => 1 
        [parent_id] => 0 
        [title] => test 
        [url] => http://www.test.com 
        [slug] => www_test_com 
        [keywords] => cpc,seo 
        [language_id] => 1 
       ) 
      [SiteMeta] => Array 
       (
        [0] => Array 
         (
          [id] => 1 
          [site_id] => 1 
          [key] => pagerank 
          [value] => 5 
          [created] => 2010-08-03 00:00:00 
         ) 

        [1] => Array 
         (
          [id] => 2 
          [site_id] => 1 
          [key] => pagerank 
          [value] => 2 
          [created] => 2010-08-17 00:00:00 
         ) 

        [2] => Array 
         (
          [id] => 5 
          [site_id] => 1 
          [key] => alexa 
          [value] => 1900000 
          [created] => 2010-08-10 17:39:06 
         ) 
       ) 
     ) 

要获得的PageRank我只是遍历所有的网站和操纵这个数组我得到。接下来我用Set :: extract过滤结果。但这种感觉不太对劲:)

$sitesToCheck = $this->paginate($this->_searchConditions($this->params)); 

foreach($sitesToCheck as $site) { 
      $pagerank = $this->_getPageRank($site['Site']); 
      $alexa = $this->_getAlexa($site['Site']); 
      $site['Site']['pagerank'] = $pagerank; 
      $sites[] = $site; 
     } 

if (isset($this->params['named']['gpr']) && $this->params['named']['gpr']) { 
       $rank = explode('-', $this->params['named']['gpr']); 
         $min = $rank[0];$max = $rank[1]; 
       $sites = Set::extract('/Site[pagerank<=' . $max . '][pagerank>=' . $min .']', $sites); 
     } 

$this->set(compact('sites', 'direction'));   

请问你们帮我考虑一下这个解决方案吗?提前致谢。


感谢您的贡献。我尝试了这些选项(也有一些与bindmodel但不工作),但仍然无法让它工作,因为它应该是。如果我定义这个

$this->paginate = array(
        'joins'=> array(
           array(
            'table'=>'site_metas', 
            'alias'=>'SiteMeta', 
            'type' =>'inner', 
            'conditions' =>array('Site.id = SiteMeta.site_id') 
            )             
         ),                 
     ); 

我得到重复的结果 我有3所不同的SiteMeta记录的网站,并与2个不同的记录中的网站。 paginate方法总共返回5条记录。这可能是一个简单的解决方案,但我不知道它:)

另外我试图自己写一个SQL查询,但似乎我不能使用分页魔术在这种情况下。查询我想模仿分页选项和条件如下。查询返回完全按照我想要的。

$sites = $this->Site->query('SELECT * FROM sites Site, site_metas SiteMeta WHERE SiteMeta.id = (select SiteMeta.id from site_metas SiteMeta WHERE Site.id = SiteMeta.site_id AND SiteMeta.key = \'pagerank\' order by created desc limit 0,1)'); 
+0

所以你要在有结果,而不是你PAGINATE什么阵列?或者你想要产生什么SQL查询? – bancer 2010-08-18 22:22:12

+0

感谢您的快速回复。 我正在考虑在SiteMeta索引中只有一个项目的数组,而不是示例中的3。我希望能够调用该记录的值,因此我不必循环访问数组并通过添加一些索引为pagerank或alexa来自己更改数组。 这可以实现吗? 一个更好更清洁的解决方案的建议也可以嘿嘿:) – Laurent 2010-08-19 00:05:43

回答

2

由于您试图在hasMany关系中检索数据,因此cakephp默认情况下不会加入表。如果你去joins你可以这样做:

$this->paginate = array(
        'joins'=>array(
           array(
           'table'=>'accounts', 
           'alias'=>'Account', 
           'type' =>'inner', 
           'conditions' =>array('User.id = Account.user_id') 
          ) 
          ), 
          'conditions'=> array('OR' => 
           array(
           'Account.name'=>$this->params['named']['nickname'], 
           'User.id' => 5) 
           ) 
          ); 
$users = $this->paginate(); 
     $this->set('users',$users); 
debug($users); 
$this->render('/users/index'); 

你有这个根据你当然需要适应。 More加入,就像在另一个答案中已经提到的一样。

编辑1:这是因为你错过了第二个'条件'。看我的代码片段。第一个“条件”只是表明联结发生的地方,而第二个“条件”则表示实际选择。

编辑2:Here有关如何编写条件以选择所需数据的一些信息。您可能希望在您的优化条件下使用您的rdbms的max函数列created

编辑3:可容纳和连接不应该一起使用。从手册中引用:使用包含行为的连接可能会导致一些SQL错误(重复表),因此如果您的主要目标是根据相关数据执行搜索,则需要使用连接方法作为Containable的替代方法。可封装最适合限制查找语句带来的相关数据量。我想,你还没有尝试过编辑2。

编辑4:一种可能的解决方案可能是将字段last_updated添加到表Sites。然后可以在第二个条件语句中使用该字段,以与SiteMeta.created值进行比较。

+0

嗨,我不认为这是问题。当我添加这个 'conditions'=> array('Site.title'=>'test') 我还是得到了3条记录,因为标题为'test'的网站有3个SiteMeta记录。我不太明白... – Laurent 2010-08-19 15:52:59

+0

嗨洛朗, 你必须改进(第二)条件,请参阅编辑2.顺便说一句,你似乎是在正确的轨道上,只是提炼。 – benjamin 2010-08-19 16:33:20

+0

提示添加编辑2 – benjamin 2010-08-19 16:47:41

0

尝试是这样的:

$this->paginate = array(
     'fields'=>array(
      'Site.*', 
      'SiteMeta.*', 
      'MAX(SiteMeta.created) as last_date' 
     ), 
     'group' => 'SiteMeta.key' 
     'conditions' => array(
      'SiteMeta.key' => 'pagerank' 
     ) 
    ); 
    $data = $this->paginate('Site'); 

或者这样:

$conditions = array(
     'recursive' => 1, 
     'fields'=>array(
      'Site.*', 
      'SiteMeta.*', 
      'MAX(SiteMeta.created) as last_date' 
     ), 
     'group' => 'SiteMeta.key' 
     'conditions' => array(
      'SiteMeta.key' => 'pagerank' 
     ) 
    ); 
    $data = $this->Site->find('all', $conditions); 

如果不工作检查thisthis。我100%确定可以通过单个查询来获得想要的结果。

0

尝试是这样的(与中容纳设置的所有机型):

$this->Site->recursive = -1; 

$this->paginate = array(
    'conditions' => array(
     'Site.title' => 'title') //or whatever conditions you want... if any 
    'contain' => array(
     'SiteMeta' => array(
      'conditions' => array(
       'SiteMeta.key' => 'pagerank'), 
      'limit' => 1, 
      'order' => 'SiteMeta.created DESC'))); 

我使用中容纳这么多,其实我有这个在我的app_model文件,所以它适用于所有型号:

var $actsAs = array('Containable'); 
0

许多人认为所有设法帮助我的人通过这个:) 我得到了它固定的所有嘿嘿。

最终,这一直是招对我来说

$this->paginate = array(
        'joins'=> array(
            array(
             'table'=>'site_metas', 
             'alias'=>'SiteMeta', 
             'type' =>'inner', 
             'conditions' => array('Site.id = SiteMeta.site_id'))                  
           ), 
        'group' => 'Site.id', 
        'contain' => array(
         'SiteMeta' => array(
           'conditions' => array(
            'SiteMeta.key' => 'pagerank'), 
            'limit' => 1, 
            'order' => SiteMeta.created DESC', 
            ))); 

     $sites = $this->paginate(); 
+0

第3编辑部分增加了。 – benjamin 2010-08-19 19:33:40

+0

嘿洛朗, 很高兴你做到了。我在其他地方看到了一个解决方案,一些接近核心开发人员的人帮助某人组装更大的蛋糕声明。该解决方案与您的混合连接和包含一样,似乎在手册中不受欢迎:http://book.cakephp.org/view/1047/Joining-tables。然而,我发现了一个蛋糕贡献者在没有问题的情况下做了类似事情的代码。底线,当某些时候发生SQL错误时,省略可容纳的行为。 你的, – benjamin 2010-08-21 10:40:25