Laravel Eloquent Join 与 Inner Join?

问题描述 投票:0回答:3

所以我在弄清楚如何进行 feed 风格的 mysql 调用时遇到了一些麻烦,我不知道这是一个雄辩的问题还是 mysql 的问题。我确信两者都是可能的,我只是需要一些帮助。

所以我有一个用户,他们进入他们的提要页面,在此页面上显示来自他们朋友的内容(朋友投票、朋友评论、朋友状态更新)。假设我有汤姆、蒂姆和泰勒作为我的朋友,我需要获得他们所有的投票、评论和状态更新。我该怎么办?我有一个按 ID 号列出的所有朋友的列表,并且有每个事件(投票、评论、状态更新)的表格,其中存储了 Id 以链接回用户。那么我怎样才能一次获得所有这些信息,以便我可以将其以以下形式显示在提要中:

蒂姆评论“酷”

泰勒说“哇第一次状态更新~!”

泰勒被评为“有史以来最好的比赛”

编辑@damiani 因此,在进行模型更改后,我有这样的代码,并且它确实返回了正确的行

$friends_votes = $user->friends()->join('votes', 'votes.userId', '=', 'friend.friendId')->orderBy('created_at', 'DESC')->get(['votes.*']);
$friends_comments = $user->friends()->join('comments', 'comments.userId', '=', 'friend.friendId')->orderBy('created_at', 'DESC')->get(['comments.*']);
$friends_status = $user->friends()->join('status', 'status.userId', '=', 'friend.friendId')->orderBy('created_at', 'DESC')->get(['status.*']);

但我希望它们全部同时发生,这是因为 mysql 按顺序对数千条记录进行排序比 php 获取 3 个列表、合并它们然后执行此操作快 100 倍。有什么想法吗?

php mysql sql laravel eloquent
3个回答
47
投票

我确信还有其他方法可以实现此目的,但一种解决方案是通过查询生成器使用

join

如果您的桌子设置如下:

users
    id
    ...

friends
    id
    user_id
    friend_id
    ...

votes, comments and status_updates (3 tables)
    id
    user_id
    ....

在您的User模型中:

class User extends Eloquent {
    public function friends()
    {
        return $this->hasMany('Friend');
    }
}

在您的朋友模型中:

class Friend extends Eloquent {
    public function user()
    {
        return $this->belongsTo('User');
    }
}

然后,要收集 id 为 1 的用户好友的所有投票,您可以运行以下查询:

$user = User::find(1);
$friends_votes = $user->friends()
    ->with('user') // bring along details of the friend
    ->join('votes', 'votes.user_id', '=', 'friends.friend_id')
    ->get(['votes.*']); // exclude extra details from friends table

join
comments
表运行相同的
status_updates
。如果您希望投票、评论和 status_updates 位于一个按时间顺序排列的列表中,您可以将生成的三个集合合并为一个,然后对合并后的集合进行排序。


编辑

要在一个查询中获取投票、评论和状态更新,您可以构建每个查询,然后合并结果。不幸的是,如果我们使用 Eloquent

hasMany
关系(请参阅此问题的评论以了解该问题的讨论),这似乎不起作用,因此我们必须修改查询以使用
where
代替:

$friends_votes = 
    DB::table('friends')->where('friends.user_id','1')
    ->join('votes', 'votes.user_id', '=', 'friends.friend_id');

$friends_comments = 
    DB::table('friends')->where('friends.user_id','1')
    ->join('comments', 'comments.user_id', '=', 'friends.friend_id');

$friends_status_updates = 
    DB::table('status_updates')->where('status_updates.user_id','1')
    ->join('friends', 'status_updates.user_id', '=', 'friends.friend_id');

$friends_events = 
    $friends_votes
    ->union($friends_comments)
    ->union($friends_status_updates)
    ->get();

但此时,我们的查询变得有点复杂,因此与额外表(如下面的 DefiniteIntegral 建议的那样)的多态关系可能是一个更好的主意。


5
投票

可能不是您想听到的,但是“提要”表将是此类事务的一个很好的中间人,为您提供一种非规范化的方式来以多态关系转向所有这些数据。

你可以像这样构建它:

<?php

Schema::create('feeds', function($table) {
    $table->increments('id');
    $table->timestamps();
    $table->unsignedInteger('user_id');
    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    $table->morphs('target'); 
});

像这样构建 feed 模型:

<?php

class Feed extends Eloquent
{
    protected $fillable = ['user_id', 'target_type', 'target_id'];

    public function user()
    {
        return $this->belongsTo('User');
    }

    public function target()
    {
        return $this->morphTo();
    }
}

然后使用以下内容保持最新状态:

<?php

Vote::created(function(Vote $vote) {
    $target_type = 'Vote';
    $target_id   = $vote->id;
    $user_id     = $vote->user_id;

    Feed::create(compact('target_type', 'target_id', 'user_id'));
});

您可以使上述内容更加通用/强大 - 这仅用于演示目的。

此时,您的提要项目真的很容易一次检索所有:

<?php

Feed::whereIn('user_id', $my_friend_ids)
    ->with('user', 'target')
    ->orderBy('created_at', 'desc')
    ->get();

-1
投票

内连接是一种数据库操作,它根据两个或多个表之间的相关列组合来自两个或多个表的行。多个条件允许我们指定更复杂的关系来连接表。 Laravel 的 Eloquent 使这个过程无缝且可读。

https://websolutioncode.com/laravel-eloquent-inner-join-with-multiple-conditions

© www.soinside.com 2019 - 2024. All rights reserved.