2015-11-26 89 views
1

我有PostsTags模型,與「屬於多個」關聯。CakePHP 3.x:查詢相關帖子

所以在我的數據庫中,我有poststags表和posts_tagspost_idtag_id領域。 tags表具有post_count字段,顯示屬於該標籤的帖子數量。

當我得到一篇文章,我也得到與它相關的標籤。現在

$this->Posts->find() 
    ->contain(['Tags']) 
    ->where(['Posts.id' => $id]) 
    ->first()); 

,對於每一個標籤,我想獲得的是有標籤的帖子,但不包括最初的帖子,整理創建日期(created場)。 重要的是,每個標籤都獲得了已經獲得的職位以外的職位。

我可以使用一個foreach和每個標籤獲取包含它的職位,通過排除初始職位的ID和已經獲得的職位。

我想知道如果我可以用單個查詢來做到這一點,並有一個工作的例子。

謝謝。


編輯
臨時的解決方案,它採用了查詢每個標籤

首先,我得到的主要職務:

$post = $this->Posts->find() 
    ->contain(['Tags']) 
    ->where(['Posts.id' => $id]) 
    ->first(); 

在這種情況下,後恢復通過它的ID,但你可以做不同的事情。你也可以使用緩存。
重要的東西$post變量。

現在(在這裏是一個好主意,使用緩存...):

//Tries to gets related posts from cache 
$related = Cache::read($cache = sprintf('related_posts_for_%s', $post->id), 'posts'); 

if(empty($related)) { 
    $tags = $post->tags; 

    //Re-orders tags, using the "post_count" field, then based on the popularity of tags 
    usort($tags, function($a, $b) { return $b['post_count'] - $a['post_count']; }); 

    //Gets only the first 5 tags 
    $tags = array_slice($tags, 0 , 5); 

    //This array will be contain the ID to be excluded 
    $exclude = [$post->id]; 

    //Gets a related post for each tag 
    //Reveres the tags order, because the tags less popular have less chance to find a related post 
    foreach(array_reverse($tags) as $tag) { 
     $post = $this->Posts->find('active') 
      ->select(['id', 'title', 'slug']) 
      ->matching('Tags', function($q) use($tag) { 
       return $q->where(['Tags.id' => $tag->id]); 
      }) 
      ->where(['Posts.id NOT IN' => $exclude]) 
      ->first(); 

     //Adds the post to the related posts and its ID to the IDs to be excluded for the next query 
     if(!empty($post)) { 
      $related[] = $post; 
      $exclude[] = $post->id; 
     } 
    } 

    Cache::write($cache, $related, 'posts'); 
} 

//Related posts 
debug($related); 

注:此代碼後,$post變量不再包含原來的職位。請注意或爲相關帖子使用不同的變量名稱。

回答

1

試試這個(未測試)

$this->Posts->find() 
->contain([ 
    'Tags', 
    'Tags.Posts' => function($q) use($id) { 
     $q->where(['id !=' => $id]) 
      ->order(['created' => 'desc']) 
      ->limit(1); 
     return $q; 
    } 
    ]) 
->where(['Posts.id' => $id]) 
->first()); 

但這種方式你可能會得到一個郵政兩次(我現在看到的是你不想要這個)

+0

感謝@arilia 。但我想分開這兩個查詢。我想這是同樣的事情,但使用'匹配()'。這樣對嗎?但在這種情況下有一個問題:此代碼可能需要兩次相同的職位? –

+0

我不明白:你在OP中說你只想要一個查詢,現在你想要兩個。 – arilia

+0

假設我的文章有'a'和'b'標籤。另一篇文章有​​相同的標籤。同一篇文章(第二篇)將被獲得兩次,每個標籤? –