laravel eloquent сортировать по отношениям

У меня 3 модели

  • пользователь
  • канал
  • Ответить

модельные отношения

  • user есть belongsToMany('App\Channel');
  • channel имеет hasMany('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 

EDIT также, я пробовал это. да, я получил ожидаемый результат, но он не будет загружать весь канал, если нет ответа.

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

РЕДАКТИРОВАТЬ:

запрос результат

По моим сведениям, нетерпеливая загрузка методом запускает второй запрос. Вот почему вы не можете достичь того, чего хотите, с энергичной загрузкой методом.

Я думаю, что метод 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 атрибут 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(); 

Во-первых, вам не нужно указывать имя сводной таблицы, если вы следуете соглашению об именах Laravel, чтобы ваш код выглядел немного чище:

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