2010-08-18 68 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