You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中能否同时对Base表与Pivot表排序,展示最新记录

问题

能否同时对Base表(UserDocument)和Pivot表(share_documents)进行排序?我希望将最新的记录(无论是用户自有文档还是共享文档)展示在列表顶部。

当前代码实现:

public function get_user_documents()
{
    $userId = Auth::id();
    $user_documents = UserDocument::where('user_id', $userId)
        ->orWhereHas('share_documents', function ($query) use ($userId) {
            $query->where('users.id', $userId);
        })
        ->with(['share_documents' => function ($query) use ($userId) {
            $query->where('users.id', $userId);
        }])
        ->latest()
        ->get();

    // $user_documents = $user_documents->map(function ($document) use ($userId) {
    //     $status = $document->user_id == $userId ? 'owned' : 'shared';
    //     $document->status = $status;
    //     return $document;
    // });
    return response()->json($user_documents);
}
解决方案

可以实现,核心思路是取自有文档的时间字段、共享记录的时间字段这两个值里的最大值,然后按这个最大值排序。以下是两种可行的实现方式:

方式一:数据库层面排序(推荐)

直接在SQL查询阶段计算每个文档的最新时间,性能更优,适合数据量较大的场景。假设UserDocument表有created_at字段,share_documents中间表有created_at字段:

public function get_user_documents()
{
    $userId = Auth::id();
    $user_documents = UserDocument::select('user_documents.*')
        // 计算每个文档的最新时间:自有文档用自身时间,共享文档取共享记录的时间
        ->selectRaw('GREATEST(user_documents.created_at, COALESCE(share_documents.created_at, user_documents.created_at)) as latest_time')
        ->leftJoin('share_documents', function ($join) use ($userId) {
            $join->on('user_documents.id', '=', 'share_documents.user_document_id')
                 ->where('share_documents.user_id', '=', $userId);
        })
        ->where(function ($query) use ($userId) {
            $query->where('user_documents.user_id', $userId)
                  ->orWhereNotNull('share_documents.id');
        })
        ->groupBy('user_documents.id') // 避免同一文档因共享记录重复出现
        ->orderBy('latest_time', 'desc')
        ->with(['share_documents' => function ($query) use ($userId) {
            $query->where('user_id', $userId);
        }])
        ->get();

    // 可选:给文档添加自有/共享的状态标识
    $user_documents->map(function ($document) use ($userId) {
        $document->status = $document->user_id == $userId ? 'owned' : 'shared';
        return $document;
    });

    return response()->json($user_documents);
}

关键说明

  • GREATEST():取两个时间字段中的较大值
  • COALESCE():处理无共享记录的情况,默认使用文档自身的时间
  • leftJoin:关联共享表以获取共享记录的时间
  • groupBy:确保同一文档只返回一条结果

方式二:集合层面排序

如果不想修改数据库查询逻辑,可以在获取数据集合后,通过PHP计算每个文档的最新时间再排序:

public function get_user_documents()
{
    $userId = Auth::id();
    $user_documents = UserDocument::where('user_id', $userId)
        ->orWhereHas('share_documents', function ($query) use ($userId) {
            $query->where('user_id', $userId);
        })
        ->with(['share_documents' => function ($query) use ($userId) {
            $query->where('user_id', $userId);
        }])
        ->get();

    // 计算最新时间并排序
    $user_documents = $user_documents->map(function ($document) use ($userId) {
        $document->status = $document->user_id == $userId ? 'owned' : 'shared';
        // 取共享记录中的最新时间,无共享记录则用文档自身时间
        $shareLatest = $document->share_documents->max('created_at');
        $document->latest_time = $shareLatest ?: $document->created_at;
        return $document;
    })->sortByDesc('latest_time')->values();

    return response()->json($user_documents);
}

关键说明

  • max('created_at'):从共享记录集合中取出最新的时间
  • sortByDesc():按最新时间倒序排列
  • values():重置集合的键名,避免返回的JSON出现非连续索引

注意事项

  • 确保share_documents中间表存在时间字段(如created_at或updated_at),若没有需先添加
  • 若想更准确反映文档的最新变动,可将created_at替换为updated_at
  • 数据量大时优先选择数据库层面排序,性能更优

内容的提问来源于stack exchange,提问作者Hassan Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 16:27:43