laravel elaborent sort by relationship

nc1teljy  于 2023-04-07  发布在  其他
关注(0)|答案(5)|浏览(91)

我有3个模型

  • 用户
  • 渠道
  • 回复

模型关系

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

假设我有两个频道

  • 通道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');
}
ldfqzlk8

ldfqzlk81#

据我所知,渴望加载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')获取频道列表order by replies created_at属性。
对于像channel这样的条件(可能有回复,也可能没有回复),使用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();
r3i60tvu

r3i60tvu2#

在你的channel类中,你需要创建这个hasOne关系(你的channel hasManyreplies,但它hasOnelatest reply):

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');
}
wztqucjr

wztqucjr3#

首先,如果你遵循Laravel的命名约定,你不必指定pivot表的名称,这样你的代码看起来会更干净:

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');
}
zzzyeukh

zzzyeukh4#

如果你有一个hasOne()关系,你可以通过执行以下操作对所有记录进行排序:

$results = Channel::with('reply')
                   ->join('replies', 'channels.replay_id', '=', 'replies.id')
                   ->orderBy('replies.created_at', 'desc')
                   ->paginate(10);

这将按照最新的回复对所有的channels记录进行排序(假设每个通道只有一个回复)。

bq8i3lrv

bq8i3lrv5#

尝试这个希望工作..我已经使用了相同的在我以前的项目。

public function channels()
{
    return $this->belongsToMany('App\Channel', 'channel_user')
                ->withPivot('is_approved')
                ->leftJoin('replies', 'channels.id', '=', 'replies.channel_id')
                ->select('channels.*')
                ->groupBy('channels.id')
                ->orderByRaw('MAX(replies.created_at) DESC');
}

相关问题