首页 > 解决方案 > 返回分组结果数组

问题描述

注意:我使用的是 Laravel 5.3。

我有一张桌子,comments看起来像这样:

+====+=========+
| id | message |
+====+=========+
|  1 |      Hi |
|  2 |   World |
+====+=========+

我有第二张表,comment_stats它跟踪每条评论的总票数,如下所示:

+====+============+=======+
| id | comment_id | votes |
+====+============+=======+
|  1 |          1 |    10 |
|  2 |          2 |     0 |
+====+============+=======+

最后,我有第三张表,comment_votes它跟踪每个用户对每条评论的投票,如下所示:

+====+============+=========+=========+
| id | comment_id | user_id |    type |
+====+============+=========+=========+
|  1 |          1 |      10 |       0 |
|  2 |          1 |       9 |       0 |
|  3 |          1 |       8 |       1 |
|  4 |          1 |       7 |       2 |
|  5 |          1 |       6 |       1 |
|  6 |          1 |       5 |       5 |
|  7 |          1 |       4 |       3 |
|  8 |          1 |       3 |       3 |
|  9 |          1 |       2 |       1 |
| 10 |          1 |       1 |       0 |
+====+============+=========+=========+

如您所见,每条评论都可以由其他用户投票 ( comment_votes),并且总投票数记录在 中comment_stats。每张选票都有一个type。总共有 6 个可能type的 s (0-5)。

我现在的Comment.php班级看起来像:

class Comment extends Model
{
    protected $with = [
        'votes', 'stats'
    ];

    public function votes()
    {
        return $this->hasMany('App\Vote');
    }

    public function stats()
    {
        return $this->hasOne('App\Stat');
    }
}

我的Stat.php课看起来像:

class Stat extends Model
{
    protected $with = [
        'topTypes'
    ];

    public function comment()
    {
        return $this->belongsTo('App\Comment');
    }

    public function topTypes()
    {
        // Need to return an array of the top 3 types here
    }
}

我的Vote.php课看起来像:

class Vote extends Model
{
    public function comment()
    {
        return $this->belongsTo('App\Comment');
    }
}

我想检索type每条评论的前 3 票。所以对于comment_id = 1,输出将是[0, 1, 3](作为一个数组),按这个顺序。0 出现 3 次,1 出现 3 次,3 出现两次。如果有平局,它应该得到较低的整数type

我试图让 JSON 最终看起来像这样,因此它top_types是以下内容的一部分stats

{
    "id": 1,
    "message": "Hi",
    "stats": {
        "id": 1,
        "comment_id": 1,
        "votes": 10,
        "top_types": [0, 1, 3]
    }
}

我怎么能做到这一点?所有这些关系都让我发疯。

标签: laravellaravel-5eloquent

解决方案


获得结果很简单。

$result = app(Comment::class)->with('stats.topTypes')->find(1);

接下来,由于您只需要前 3 种类型而不是全部类型,请过滤我们的急切加载查询。

$result = app(Comment::class)->with('stats.topTypes', function (Eloquent\Builder $query) {
    $query->limit(3);
})->find(1);

请参阅:约束急切负载

如果这将成为该模型的常见用途,您可能会考虑将该行为移至Query Scope。请注意不要在任何模型类中加载过多的业务逻辑。这可能很诱人,但有点反模式,因为这并不是 MVC 模型层的真正用途。

另一种选择是在方法中将您的限制应用于实际的关系定义Stat::topTypes()。同样,只有在您确定该关系的所有用例都只需要 3 个结果时才这样做。您也可以在orderByDesc('createdAt')那里放置一个,这可能在调用案例中更有用。

最后,由于您不想要完整的 Type 模型结果,而只是一个 ID 数组,请记住嵌套结果将采用 Eloquent\Collection 对象的形式,它是 Suppot\Collection 的子对象,可以访问所有相同的钟声和口哨声:

$result->stats->topTypes->transform(function (Type $type) {
    return $type->getKey();
});

请参阅:集合(转换)


推荐阅读