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

Laravel ORM如何按子模型投票总数对选项排序?

实现方案

1. 确认模型关联定义

先确保三个模型的关联关系配置正确:

Issue 模型(app/Models/Issue.php)

class Issue extends Model
{
    // 关联当前议题下的所有选项
    public function options()
    {
        return $this->hasMany(Option::class);
    }
}

Option 模型(app/Models/Option.php)

class Option extends Model
{
    // 关联当前选项下的所有投票记录
    public function votes()
    {
        return $this->hasMany(Vote::class);
    }
}

Vote 模型(app/Models/Vote.php)

class Vote extends Model
{
    // 关联投票所属的选项
    public function option()
    {
        return $this->belongsTo(Option::class);
    }
}

2. 实现选项按投票数降序加载

有两种实现方式,可根据业务场景选择:

方式一:查询时动态指定排序(适合仅特定页面需要排序的场景)

在控制器查询议题数据时,通过预加载关联的方式,统计每个选项的投票数并按降序排序:

$issues = Issue::with(['options' => function ($query) {
    // 统计投票数并按降序排列选项
    $query->withCount('votes')->orderBy('votes_count', 'desc');
}])->get();

方式二:关联中默认排序(适合所有场景都需要按投票数排序的情况)

直接在Issue模型的options关联中加入统计和排序逻辑,后续每次加载选项都会自动按投票数降序排列:

public function options()
{
    return $this->hasMany(Option::class)
                ->withCount('votes')
                ->orderBy('votes_count', 'desc');
}

此时控制器只需正常查询即可:

$issues = Issue::with('options')->get();

3. Blade模板遍历显示

模板中直接遍历$issues即可,每个议题下的选项已经按投票数降序排列,votes_count是withCount自动生成的统计属性:

@foreach($issues as $issue)
    <div class="issue-container">
        <h3>{{ $issue->title }}</h3>
        <div class="options-list">
            @foreach($issue->options as $option)
                <div class="option-item">
                    <span>{{ $option->content }}</span>
                    <span class="vote-num">投票数:{{ $option->votes_count }}</span>
                </div>
            @endforeach
        </div>
    </div>
@endforeach

补充说明

  • withCount()是Laravel ORM提供的高效统计方法,自动生成统计字段并避免N+1查询问题
  • 如果需要实时更新投票数(比如投票后无需刷新页面),可以结合AJAX更新前端数据,ORM层面的排序逻辑无需改动

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 05:05:19