Laravel Eloquent加入vs Inner Join?

CMO*_*MOS 22 php mysql sql laravel eloquent

所以我在搞清楚如何进行feed风格的mysql调用时遇到了一些麻烦,我不知道它是一个雄辩的问题还是一个mysql问题.我相信这两种情况都有可能,我只是需要一些帮助.

所以我有一个用户,他们去他们的供稿页面,在这个页面上它显示他们的朋友的东西(朋友投票,朋友评论,朋友状态更新).所以说我有汤姆,蒂姆和泰勒作为我的朋友,我需要得到他们所有的选票,评论,状态更新.我该怎么做?我有一个Id号码的所有朋友的列表,我有每个事件(投票,评论,状态更新)的表,其中存储了Id以链接回用户.那么我怎样才能一次获得所有这些信息,以便我可以以一种形式在Feed中显示它.

蒂姆评论说"酷"

泰勒说"Woot第一次状态更新〜!"

泰勒被评为"有史以来最佳竞争"

编辑@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.*']);
Run Code Online (Sandbox Code Playgroud)

但我希望它们一下子发生,这是因为mysql按顺序排序数千条记录比使用3个列表,合并它们然后再进行操作快100倍.有任何想法吗?

dam*_*ani 34

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

如果您有表格设置如下:

users
    id
    ...

friends
    id
    user_id
    friend_id
    ...

votes, comments and status_updates (3 tables)
    id
    user_id
    ....
Run Code Online (Sandbox Code Playgroud)

在您的用户模型中:

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

在你的朋友模型中:

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

然后,要收集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
Run Code Online (Sandbox Code Playgroud)

joincommentsstatus_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();
Run Code Online (Sandbox Code Playgroud)

但是,在这一点上,我们的查询有点毛茸茸,所以与多余的关系和一个额外的表(如下面的DefiniteIntegral建议)可能是一个更好的主意.


Def*_*ral 5

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

\n\n

你可以这样构建它:

\n\n
<?php\n\nSchema::create(\'feeds\', function($table) {\n    $table->increments(\'id\');\n    $table->timestamps();\n    $table->unsignedInteger(\'user_id\');\n    $table->foreign(\'user_id\')->references(\'id\')->on(\'users\')->onDelete(\'cascade\');\n    $table->morphs(\'target\'); \n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

像这样构建 feed 模型:

\n\n
<?php\n\nclass Feed extends Eloquent\n{\n    protected $fillable = [\'user_id\', \'target_type\', \'target_id\'];\n\n    public function user()\n    {\n        return $this->belongsTo(\'User\');\n    }\n\n    public function target()\n    {\n        return $this->morphTo();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后保持最新状态,例如:

\n\n
<?php\n\nVote::created(function(Vote $vote) {\n    $target_type = \'Vote\';\n    $target_id   = $vote->id;\n    $user_id     = $vote->user_id;\n\n    Feed::create(compact(\'target_type\', \'target_id\', \'user_id\'));\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以使上面的内容更加通用/强大\xe2\x80\x94这仅用于演示目的。

\n\n

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

\n\n
<?php\n\nFeed::whereIn(\'user_id\', $my_friend_ids)\n    ->with(\'user\', \'target\')\n    ->orderBy(\'created_at\', \'desc\')\n    ->get();\n
Run Code Online (Sandbox Code Playgroud)\n