laravel雄辩地按关系排序

Hit*_*ori 11 php mysql laravel laravel-5

我有3个型号

  • 用户
  • 渠道
  • 答复

模范关系

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

假设我有2个频道 - 频道1 - 频道2

channel-2 有最新的答复 channel-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
Run Code Online (Sandbox Code Playgroud)

编辑 也,我试过这个.是的,我确实得到了预期的结果,但如果没有回复,它将不会加载所有频道.

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');
}
Run Code Online (Sandbox Code Playgroud)

编辑:

询问结果

Ste*_*ung 11

据我所知,eager load 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();
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过回复属性调用$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();
    }
Run Code Online (Sandbox Code Playgroud)

编辑:

如果要向groupBy查询添加方法,则必须特别注意您的orderBy子句.因为在Sql性质中,Group By子句先运行在Order By子句之前.请参阅此stackoverflow问题详细说明此问题.

因此,如果添加groupBy方法,则必须使用orderByRaw方法,并且应该像下面这样实现.

return $this->channels()
                ->leftJoin('replies', 'channels.id', '=', 'replies.channel_id')
                ->groupBy(['channels.id'])
                ->orderByRaw('max(replies.created_at) desc')
                ->get();
Run Code Online (Sandbox Code Playgroud)

  • 因为连接表的字段将位于同一行,所以可以进行排序。 (2认同)
  • 所以我使用了这样的 join 方法。`return $this->belongsToMany('App\Channel', 'channel_user') ->withPivot('is_approved') ->join('replies', 'replies.channel_id', '=', 'channels.id') ->orderBy('replies.created_at', 'DESC');` 但是当特定频道没有回复时。这会导致错误。 (2认同)