Laravel:限制嵌套关系

时间:2016-06-09 16:27:39

标签: php laravel

以下是我必须使用关联的Discussionsthreads获取所有posts的代码。我试图将帖子的数量限制为1.当我这样做时,我希望每个帖子中只有1个帖子,但是9个帖子中没有帖子,1个帖子中有1个帖子。

App\Discussion::with([
    'threads' => function ($query) => {
        // Correctly limits the number of threads to 10.
        $query->latest()->take(10);
    },
    'threads.posts' => function ($query) {
        // Limits all posts to 1, not each post to 1 for each thread.  
        $query->take(1);
    }
])->where(['slug' => 'something'])->firstOrFail();

上面的代码在数据库中运行以下SQL查询。

select * from `discussions` where (`slug` = ?) and `discussions`.`deleted_at` is null limit 1

select * from `threads` where `threads`.`discussion_id` in (?) and `threads`.`deleted_at` is null order by `created_at` desc limit 10

select * from `posts` where `posts`.`thread_id` in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) and `posts`.`deleted_at` is null order by `created_at` desc limit 1

我可以看到第三个查询导致问题,因为它将所有帖子限制为1。

我希望看到以下内容;一个讨论,在该主题中有10个主题和1个帖子。

{
  "id": 1,
  "title": "Discussion Title",
  ...
  "threads": [
    {
      "id": 1,
      "title": "Thread Title",
      ...
      "posts": [
        {
          "id": 1,
          "title": "Post Title",
          ...
        }
      ]
    }
    ...
  ]
}

有没有办法在Laravel框架内执行此操作,还是必须运行原始查询?我宁愿尽可能坚持使用雄辩的ORM。

2 个答案:

答案 0 :(得分:3)

你需要做一些“调整”,因为Eloquent没有查询方法来限制关系中的数字结果。

首先在Thread模型上创建此函数。

public function one_post()
{
    //OrderBy is optional
    return $this->hasOne(Post::class)->orderBy('id', 'asc');
}

现在你有一个只返回一个帖子的关系。您可以这样查询:

    App\Discussion::with([
        'threads' => function ($query) {
            // Correctly limits the number of threads to 10.
            $query
                ->latest()
                ->take(10)
                ->with('one_post');
        }
        ])->where(['slug' => 'something'])->firstOrFail();

答案 1 :(得分:1)

急切的结果不容易受到限制,但根据:https://laracasts.com/discuss/channels/eloquent/laravel-51-eloquent-relationship-hasmany-limit-records可以使用模型关系进行映射....换句话说,您的代码可能看起来像:

 App\Discussion::with([
        'threads' => function ($query) => {
            // Correctly limits the number of threads to 10.
            $query->latest()->take(10);
        }])->where(['slug' => 'something'])->firstOrFail()
        ->map(function ($thread) {
            $thread->setRelation('posts', $thread->posts->take(1));
            return $thread;
        });