Laravel Eloquent 按关系排序

新手上路,请多包涵

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

编辑:

询问结果

原文由 Hitori 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 624
1 个回答

据我所知, 急切加载 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 子句运行。请参阅 此 stackoverflow 问题 中的详细信息。

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

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

原文由 Steve.NayLinAung 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏