laravel 雄辩地按关系排序

2022-08-30 23:27:25

我有 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

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

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


答案 1

据我所知,急切加载方法运行第二次查询。这就是为什么你不能用急切的加载方法实现你想要的。withwith

我认为将方法与关系方法相结合是解决方案。以下解决方案经过全面测试,运行良好。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();
    }

编辑:

如果要向查询中添加方法,则必须特别注意您的子句。因为在 Sql 性质中,子句先在子句之前运行。请参阅此堆栈溢出问题中的详细信息。groupByorderByGroup ByOrder By

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

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

答案 2

在通道类中,您需要创建此关系(通道回复,但最新回复):hasOnehasManyhasOne

public function latestReply()
{
    return $this->hasOne(\App\Reply)->latest();
}

您现在可以按最新回复排序所有频道,如下所示:

Channel::with('latestReply')->get()->sortByDesc('latestReply.created_at');

要从按最新回复排序的用户那里获取所有频道,您需要该方法:

public function getChannelsOrderdByLatestReply()
{
    return $this->channels()->with('latestReply')->get()->sortByDesc('latestReply.created_at');
}

其中由以下人员给出:channels()

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

推荐