2016-11-28 262 views
5

我有3種型號laravel雄辯排序關係

  • 用戶
  • 通道
  • 回覆

模型關係

  • userbelongsToMany('App\Channel');
  • channelhasMany('App\Reply', 'channel_id', 'id')->oldest();

比方說,我有2個通道 - 通道1 - 通道2

channel-2channel-1

最新回覆,現在,我想訂購用戶的通道通過其頻道的當前答覆。 就像一些聊天應用程序。 我該如何訂購用戶的頻道?

  • 通道2
  • 信道-1

我已經嘗試過的一些代碼。但沒有發生

// User Model 
public function channels() 
    { 
     return $this->belongsToMany('App\Channel', 'channel_user') 
        ->withPivot('is_approved') 
        ->with(['replies']) 
        ->orderBy('replies.created_at'); // error 

    } 
// also 
public function channels() 
    { 
     return $this->belongsToMany('App\Channel', 'channel_user') 
        ->withPivot('is_approved') 
        ->with(['replies' => function($qry) { 
         $qry->latest(); 
        }]); 
    } 
// but i did not get the expected result 

編輯 還,我想這一點。是的,我確實得到了預期的結果,但如果沒有回覆,它不會加載所有頻道。

public function channels() 
{ 
    return $this->belongsToMany('App\Channel') 
       ->withPivot('is_approved') 
       ->join('replies', 'replies.channel_id', '=', 'channels.id') 
       ->groupBy('replies.channel_id') 
       ->orderBy('replies.created_at', 'ASC'); 
} 

編輯:

queryresult

+0

這種情況下,更願意「加盟」而不是「與」 –

+0

嗯,所以我不能用雄辯.. – Hitori

+0

@kap做到這一點? il.dev嗨,我試過連接方法。並按我的預期工作。但它只會返回所有有回覆的頻道。 – Hitori

回答

7

據我所知,渴望負荷with方法運行的第二個查詢。這就是爲什麼你不能達到你想要的與渴望加載with方法。

我覺得用join方法結合關係法是解決方法。以下解決方案經過充分測試並且運行良好。

// In User Model 
public function channels() 
{ 
    return $this->belongsToMany('App\Channel', 'channel_user') 
     ->withPivot('is_approved'); 
} 

public function sortedChannels($orderBy) 
{ 
    return $this->channels() 
      ->join('replies', 'replies.channel_id', '=', 'channel.id') 
      ->orderBy('replies.created_at', $orderBy) 
      ->get(); 
} 

然後就可以調用$user->sortedChannels('desc')得到渠道爲了通過回覆created_at屬性的列表。

對於像頻道(可能有或沒有答覆)的條件,只需使用leftJoin方法。

public function sortedChannels($orderBy) 
    { 
     return $this->channels() 
       ->leftJoin('replies', 'channel.id', '=', 'replies.channel_id') 
       ->orderBy('replies.created_at', $orderBy) 
       ->get(); 
    } 

編輯:

如果你想groupBy方法添加到查詢,你必須要特別注意你的orderBy條款。因爲sql性質,Group By子句在Order By子句之前先運行。請在this stackoverflow question處查看詳細的問題。

所以,如果你添加groupBy方法,你必須使用orderByRaw方法,應該像下面這樣實現。

return $this->channels() 
       ->leftJoin('replies', 'channels.id', '=', 'replies.channel_id') 
       ->groupBy(['channels.id']) 
       ->orderByRaw('max(replies.created_at) desc') 
       ->get(); 
+0

爲什麼在我們已經使用雄辯關係時使用連接,我會建議僅使用連接並通過 –

+1

應用順序。因爲連接的表的字段將位於同一行,因此可能進行排序。 –

+1

所以我用這樣的連接方法。 '返回$ this-> belongsToMany('App \ Channel','channel_user') - > withPivot('is_approved') - > join('回覆','回覆.channel_id','=','channels。 id') - > orderBy('answers.created_at','DESC');' 但是當特定頻道沒有回覆時。它會導致錯誤。 – Hitori

1

首先,你不必如果按照Laravel's naming convention指定數據透視表的名稱,以便您的代碼看起來有點清潔:

public function channels() 
{ 
    return $this->belongsToMany('App\Channel') ... 

其次,你必須調用join明確達到的效果在一個查詢:

public function channels() 
{ 
    return $this->belongsToMany(Channel::class) // a bit more clean 
     ->withPivot('is_approved') 
     ->leftJoin('replies', 'replies.channel_id', '=', 'channels.id') // channels.id 
     ->groupBy('replies.channel_id') 
     ->orderBy('replies.created_at', 'desc'); 
} 
+0

謝謝,我的代碼已經看起來像這樣。但它不會得到所有沒有答覆的頻道 – Hitori

+0

@Hitori只需使用'leftJoin',然後 –

+0

看看我的編輯。 – Hitori