Laravel Eloquent关联排序问题:按预订日期及CRT用户名排序
解决Laravel集合按预订日期+关联用户姓名排序的问题
看起来你现在的查询已经实现了按booked_on降序排列预订记录,但同日期下的用户姓名排序没生效——这是因为你在users关联里加的orderBy只是给关联的用户集合排序,并没有影响到bookings本身的排序顺序。
下面给你两种可行的解决方案:
方案一:查询层面通过关联表排序(推荐)
你可以在bookings的查询闭包里,通过join关联到crts和users表,直接基于用户姓名进行排序。这样数据库层面就能完成排序,性能更好:
$schoolBookings = SchoolModel::with([ 'bookings.crts', 'bookings.crts.users' => function($que) { $que->orderBy('first_name', 'ASC'); }, 'schoolType', 'bookings.crts.teachingSpecializations', 'bookings' => function($que) use($filters, $input) { if (!empty($input['start_date'])) { $que->where('booked_on', '>=', $input['start_date']); } if (!empty($input['end_date'])) { $que->where('booked_on', '<=', $input['end_date']); } $que->where('booked_on', '<=', date("Y-m-d 00:00:00")); // 新增关联join和排序逻辑 $que->join('crts', 'bookings.crt_id', '=', 'crts.id') // 请根据实际表关联字段调整外键 ->join('users', 'crts.user_id', '=', 'users.id') // 请根据实际表关联字段调整外键 ->orderBy('booked_on', 'desc') ->orderBy('users.first_name', 'asc') ->select('bookings.*'); // 指定选择bookings字段,避免多表字段冲突 }, ]) ->where(function($que) use ($filters, $schoolId) { // 补充$schoolId到use参数中 if (!empty($schoolId)) { $que->where('id', $schoolId); } }) ->get() ->toArray();
注意:请根据你实际的数据库表关联字段,调整
join语句里的外键(比如bookings.crt_id、crts.user_id),确保和你的表结构一致。
方案二:集合层面排序
如果不想修改查询逻辑,也可以在获取集合后,对每个学校的bookings集合进行自定义排序,适合数据量不大的场景:
$schoolBookings = SchoolModel::with([ 'bookings.crts', 'bookings.crts.users' => function($que) { $que->orderBy('first_name', 'ASC'); }, 'schoolType', 'bookings.crts.teachingSpecializations', 'bookings' => function($que) use($filters, $input) { if (!empty($input['start_date'])) { $que->where('booked_on', '>=', $input['start_date']); } if (!empty($input['end_date'])) { $que->where('booked_on', '<=', $input['end_date']); } $que->where('booked_on', '<=', date("Y-m-d 00:00:00")); $que->orderBy('booked_on', 'desc'); }, ]) ->where(function($que) use ($filters, $schoolId) { if (!empty($schoolId)) { $que->where('id', $schoolId); } }) ->get() ->map(function($school) { // 对当前学校的bookings进行自定义排序 $school->bookings = $school->bookings->sort(function($a, $b) { // 先比较预订日期(降序) $dateCompare = strcmp($b->booked_on, $a->booked_on); if ($dateCompare !== 0) { return $dateCompare; } // 日期相同则比较用户first_name(升序) $userA = $a->crts->first()->users->first()->first_name ?? ''; $userB = $b->crts->first()->users->first()->first_name ?? ''; return strcmp($userA, $userB); })->values(); // 重置集合键值,避免索引混乱 return $school; }) ->toArray();
测试任意一种方案,都能得到你想要的排序结果:先按预订日期倒序排列,同日期下按用户姓名字母升序排列。
内容的提问来源于stack exchange,提问作者Pradeep Kumar Rajput
相关产品推荐
相关产品推荐

