返回分组结果数组

时间:2021-05-17 17:26:55

标签: laravel laravel-5 eloquent

注意:我使用的是 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 (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');
    }
}

我想检索每条评论的前 3 个投票type。因此,对于 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]
    }
}

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

1 个答案:

答案 0 :(得分:0)

获得结果很简单。

$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);

见:Constraining Eager-loads

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

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

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

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

见:Collections (transform)