2014-09-22 5 views
9

Так что у меня возникли проблемы с выяснением того, как сделать вызов mysql в стиле фида, и я не знаю, является ли его красноречивая проблема или проблема mysql. Я уверен, что это возможно в обоих случаях, и мне просто нужна помощь.Laravel Eloquent Join vs Inner Join?

Итак, у меня есть пользователь, и они идут на свою страницу, на этой странице он показывает материал своим друзьям (друзьям, друзьям, друзьям, друзьям). Так что скажите, что у меня есть Том, Тим и Тейлор, как мои друзья, и мне нужно получить все свои голоса, комментарии, обновления статуса. Как мне это сделать? У меня есть список всех друзей по идентификационному номеру, и у меня есть таблицы для каждого из событий (голосов, комментариев, обновлений статуса), в которых у меня есть идентификатор, чтобы связать его с пользователем. Итак, как я могу получить всю эту информацию сразу, чтобы я мог отображать ее в фиде в форме.

Тим прокомментировал: "Классный"

Taylor Said "Woot обновление первого состояния ~!"

Тейлор Проголосовали на «конкурсе Лучший когда-либо»

Edit @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, сортируя тысячи записей в порядке, в 100 раз быстрее, чем php, беру 3 списка, объединяя их и затем делая это. Есть идеи?

+0

Как вы храните этот «список всех друзей по идентификационному номеру» .... это в таблице 'друзей', или это список, разделенный запятой, в столбце таблицы' users'? Если последний, то нормализуйте свою базу данных, чтобы затем использовать отношения модели (hasManyThrough()) –

+1

Вы можете создать представление в своем db и яркую «модель» для него. Затем просто получите все нужные вам события. В противном случае вы могли бы использовать «полиморфные» отношения: laravel.com/docs/eloquent#polymorphic-relations –

+0

, пожалуйста, не добавляйте правильный ответ на исходный вопрос, он становится все размытым, а затем – challet

ответ

17

Я уверен, что есть и другие способы, чтобы добиться этого, но одно решение было бы использовать join через Query Builder.

Если у вас есть таблицы настроить что-то вроде этого:

users 
    id 
    ... 

friends 
    id 
    user_id 
    friend_id 
    ... 

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

В вашей пользователя модель:

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

В вашем другу модель:

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

Тогда , чтобы собрать все голоса для друзей пользователя с идентификатором 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 находились в одном хронологическом списке, вы можете объединить полученные три коллекции в один, а затем отсортировать объединенную коллекцию.


Редактировать

Чтобы получить голоса, комментарии и обновления статуса в одном запросе, вы можете создать каждый запрос, а затем объединение результатов. К сожалению, это не похоже на работу, если мы используем hasMany отношения Красноречивый (see comments for this question для обсуждения этой проблемы), поэтому мы должны изменить в запросах использовать 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 предлагает ниже) могут быть лучшей идеей.

+0

Возможно, я делаю что-то неправильно, но если я запустил этот код, я получаю всю информацию для пользователя с идентификатором 1, а не с информацией о друзьях. – CMOS

+0

С некоторыми настройками я в конечном итоге получил это, чтобы работать, поэтому вы сказали, что если я хочу получать комментарии, обновления статуса и т. Д., Я должен запускать отдельные вызовы, есть ли способ получить их все сразу? – CMOS

+0

Я отредактировал ответ, чтобы включить код, который получит все 3 сразу, используя 'union'. – damiani

2

Возможно, это не то, что вы хотите услышать, но таблица «feeds» будет отличным посредником для такого рода транзакций, давая вам денормализованный способ поворота ко всем этим данным полиморфным отношениям.

Вы могли бы построить его так:

<?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'); 
}); 

Построить модель подачи следующим образом:

<?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(); 
+0

Обратите внимание также ... технически, вы могли бы сделать это с объединенным запросом, если вы морально против дополнительной таблицы. Лично я считаю, что денормализация является мощным методом для подобных ситуаций ... версия UNION будет намного более мрачной. – DefiniteIntegral

Смежные вопросы