2016-11-28 179 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