【问题标题】:Query multiple, nested Relationships in Laravel/Eloquent在 Laravel/Eloquent 中查询多个嵌套关系
【发布时间】:2015-10-06 17:40:53
【问题描述】:

我正在尝试使用 Eloquent 为 Laravel 中的帖子构建一个简单的新闻提要。

我基本上想检索所有帖子...

  • 我在哪里作者
  • 我关注的人是作者(可关注)
  • 我关注的人评论过的地方
  • 具有相同 field_id 的人是作者
  • 具有相同 school_id 的人是作者

在一个查询中。

由于我从未深入处理过联接/组合 SQL 查询,因此非常感谢您提供任何帮助!

我的桌子

users

+----+
| id |
+----+

posts

+----+-----------+-------------+
| id | author_id | author_type |
|----|-----------|-------------|
|    | users.id  | 'App\User'  |
+----+-----------+-------------+

comments

+----+----------------+------------------+-----------+-------------+
| id | commentable_id | commentable_type | author_id | author_type |
|----|----------------|------------------|-----------|-------------|
|    | posts.id       | 'App\Post'       | users.id  | 'App\User'  |
+----+----------------+------------------+-----------+-------------+

schoolables

+---------+-----------+----------+
| user_id | school_id | field_id |
+---------+-----------+----------+

followables

+-------------+---------------+---------------+-----------------+
| follower_id | follower_type | followable_id | followable_type |
|-------------|---------------|---------------|-----------------|
| users.id    | 'App\User'    | users.id      | 'App\User'      |
+-------------+---------------+---------------+-----------------+

我的模型

class Post extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
     */
    public function author()
    {
        return $this->morphTo();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

class Comment extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
     */
    public function author()
    {
        return $this->morphTo();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
     */
    public function commentable()
    {
        return $this->morphTo();
    }
}

class User extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function posts()
    {
        return $this->morphMany(Post::class, 'author')->orderBy('created_at', 'desc');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function comments()
    {
        return $this->morphMany(Comment::class, 'author')->orderBy('created_at', 'desc');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function schoolables()
    {
        return $this->hasMany(Schoolable::class);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function following()
    {
        return $this->morphMany(Followable::class, 'follower');
    }
}

【问题讨论】:

  • 那么您的尝试代码在哪里?或者你只是希望有人会为你写完整的东西?
  • @pitchinnate 我不抱任何希望,我只是想学习如何构建此类查询或为此收集更多资源。

标签: php mysql laravel eloquent laravel-5.1


【解决方案1】:

您可以尝试对这个查询使用左连接,但这会变得很复杂,因为您必须使用 leftJoins 进行所有连接,然后在所有连接上使用嵌套的 orWhere 子句

$posts = Post::leftJoin('..', '..', '=', '..')
  ->where(function($query){
    $query->where('author_id', Auth::user()->id); // being the author
  })->orWhere(function($query){
    // second clause...
  })->orWhere(function($query){
    // third clause...
  .....
  })->get();

我不认为这是可以管理的,所以我建议使用 UNIONS,http://laravel.com/docs/5.1/queries#unions

所以它会像..

$written = Auth::user()->posts();
$following = Auth::user()->following()->posts();

得到不同的查询后,没有得到结果,可以联合起来..

$posts = $written->union($following)->get();

希望这会指引你朝着正确的方向前进

【讨论】:

    【解决方案2】:

    好的,因此您要检索满足上述 5 个条件中的任何一个的所有帖子。编写此类查询的技巧是将它们分解成更小、更易于管理的部分。

    $query = Post::query();
    

    假设你是$me

    你关注的用户的id可以通过

    获取
    $followingUserIds = $me
        ->following()
        ->where('followable_type', User::class)
        ->lists('followable_id');
    

    可以获取与你相同字段的用户id

    $myFieldIds = $me->schoolables()->lists('field_id');
    $sharedFieldUserIds = Schoolable::whereIn('field_id', $myFieldIds)->lists('user_id');
    

    同样的,你也可以获得和你在同一所学校的用户

    $mySchoolIds = $me->schoolables()->lists('school_id');
    $sharedSchoolUserIds = Schoolable::whereIn('school_id', $mySchoolIds)->lists('user_id');
    

    让我们定义每个条件:

    作者在哪里

    $query->where(function($inner) use ($me) {
        $inner->where('posts.author_type', User::class);
        $inner->where('posts.author_id', $me->id);
    });
    

    我关注的人是作者(可关注)

    $query->orWhere(function($inner) use ($followingUserIds) {
        $inner->where('posts.author_type', User::class);
        $inner->whereIn('posts.author_id', $followingUserIds);
    });
    

    我关注的人评论过的地方
    这个实际上有点棘手:我们需要使用->whereHas 构造,它会找到至少有 1 条评论与子查询匹配的帖子。

    $query->orWhereHas('comments', function($subquery) use ($followingUserIds) {
        $subquery->where('comments.author_type', User::class);
        $subquery->whereIn('comments.author_id', $followingUserIds);
    });
    

    剩下的两个很简单。

    具有相同 field_id 的人是作者

    $query->orWhere(function($inner) use ($sharedFieldUserIds) {
        $inner->where('posts.author_type', User::class);
        $inner->whereIn('posts.author_id', $sharedFieldUserIds);
    });
    

    你可以看到这是怎么回事

    具有相同 school_id 的人是作者

    $query->orWhere(function($inner) use ($sharedSchoolUserIds) {
        $inner->where('posts.author_type', User::class);
        $inner->whereIn('posts.author_id', $sharedSchoolUserIds);
    });
    

    要获得匹配的帖子,您只需要这样做

    $posts = $query->get();
    

    虽然在这种特殊情况下从头开始构建查询是可行的,但如果您的需求发生变化,它将创建一个相当脆弱的结构。为了增加灵活性,您可能希望在 PostComments 模型上为每个组件构建 query scopes。这意味着您只需要一次弄清楚帖子由用户关注的人创作意味着什么,然后您只需执行Post::authoredBySomeoneFollowedByUser($me) 即可获取您关注的人创作的帖子集合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-31
      • 2020-03-19
      • 2019-02-26
      • 1970-01-01
      • 1970-01-01
      • 2015-06-27
      • 2017-10-24
      相关资源
      最近更新 更多