2017-03-31 99 views
1

使用多態關係likeable,我已經在likeable_items表中設置了authorsbooks作爲likeable_typeLaravel 5.3 - 在一個查詢中提取多態表的數據?

下面是型號:

class Like extends Model { 
    public function likeable(){ 
     return $this->morphTo(); 
    } 
} 

class Author extends Model { 
    public function likes(){ 
     return $this->morphMany('App\Like', 'likeable'); 
    } 
} 

class Book extends Model { 
    public function likes(){ 
     return $this->morphMany('App\Like', 'likeable'); 
    } 
} 

我想用一個高效的查詢到拉他們都在各自的數據,10分頁,這樣的事情不工作(我評論的代碼以顯示每一步需要什麼)。

$likeableData = 
DB::table('likeable_items') 
    // We want to fetch additional data depending on likeable_type 
    ->select(['books.title', 'books.author_name', 'book_counts.like_count']) // when likeable_type = 'book' 
    ->select(['authors.name', 'authors.country', 'authors.age', 'author_counts.like_count']) // when likeable_type = 'author' 
    ->leftJoin('books', 'books.id', '=', 'likeable_items.likeable_id') // when likeable_type = 'book' 
    ->leftJoin('book_counts', 'book_counts.book_id', '=', 'likeable_items.likeable_id') // when likeable_type = 'book' 
    ->leftJoin('author_counts', 'author_counts.author_id', '=', 'likeable_items.likeable_id') // when likeable_type = 'author' 

    // We want to have distinct results, based on unique id of book/author 
    ->distinct() 

    // We want to order by the highest like_count, regardlress of likeable_type 
    ->orderBy('book_counts.like_count', 'desc') // order by highest like_count when likeable_type = 'book' 
    ->orderBy('author_counts.like_count', 'desc') // order by highest like_count when likeable_type = 'author_counts' 

    // We want to paginate the mixed results 
    ->paginate(10); 

return $likeableData; 

如何,我可以得到不同的結果背部的最高喜歡author/book通過likes_count,各自的數據,10分頁?

UPDATE:

下面是表模式:

Table: likeable_items 
     - id 
     - likeable_id (book_id or author_id) 
     - likeable_type (book or author) 

Table: books 
     - id 
     - title 
     - author_name 

Table: book_counts 
     - book_id 
     - like_count 

Table: authors 
     - id 
     - name 
     - country 
     - age 

Table: author_counts 
     - author_id 
     - like_count 
+0

你看過你當前方法的sql結果嗎?這對我來說看起來效率並不高效 –

+0

這就是我發佈的原因,因爲我不知道如何做我在評論中的作爲一個有效的查詢:) – Wonka

+0

您的'Like'模型是否使用'likeable_items'表?你可以發佈你正在查詢的3個表格的模式嗎? –

回答

2

你可以從你的Like模型做到這一點,而不需要與一些子選擇的計數表和分組,如:

$likes = Like::select('*') 
    ->selectSub('COUNT(*)', 'total_likes') 
    ->with('likeable') 
    ->whereIn('likeable_type', [Book::class, Author::class]) 
    ->groupBy('likeable_type', 'likeable_id') 
    ->orderBy('total_likes', 'desc') 
    ->paginate(10); 

然後訪問值:

foreach($likes as $likedItem) { 
    $likedItem->total_likes; 
    if($likedItem->likeable_type === Book::class) { 
     // Your book logic here 
     $likedItem->likeable->title; 
     $likedItem->likeable->author_name; 
    } else { 
     // Your author logic here 
     $likedItem->likeable->name; 
     $likedItem->likeable->country; 
     $likedItem->likeable->age; 
    } 
} 
1

如果你願意改變架構和具有大於一個查詢可能的解決辦法是:

更新模式:

Table: likeable_items 
    - id 
    - likeable_id (book_id or author_id) 
    - likeable_type (book or author) 
    - like_count 

Table: books 
    - id 
    - title 
    - author_name 

Table: authors 
    - id 
    - name 
    - country 
    - age 

更新型號:

class Like extends Model 
{ 

    /** 
    * @return bool 
    */ 
    public function isBook() 
    { 
     return ($this->likeable_type === Book::class); 
    } 

    /** 
    * @return bool 
    */ 
    public function isAuthor() 
    { 
     return ($this->likeable_type === Author::class); 
    } 
} 

除您需要book_countsauthor_counts爲您的系統上的一個特殊的邏輯,我只是​​將它們刪除並移動like_countlikeable_items

like_countbooksauthors共有的財產,所以我認爲這是合理的將它放在likeable_items

Querires:

$likes = Like::orderBy('like_count', 'desc') 
      ->paginate(10); 

$likeable_id = $likes->pluck('likeable_id'); 

$books = Book::whereIn('id', $likeable_id)->get()->groupBy('id'); 
$authors = Author::whereIn('id', $likeable_id)->get()->groupBy('id'); 

所以,在這一點上得到最佳的10實在是微不足道。 要取數據,我們使用pluck,然後groupBy使用whereIn

關於這一點,請考慮,如果你正在使用likeable_items派遣idbooksauthors兩個whereIn將返回你需要的數據。 相反,如果使用likeable_items只是緩存booksauthors ID,則可能有一些數據,你不需要。

如何顯示內容:

@forelse ($likes as $item) 

    @if ($item->isBook()) 
     $books[$item->likeable_id][0]->title; 
     $books[$item->likeable_id][0]->author_name; 
    @else 
     $authors[$item->likeable_id][0]->name; 
     $authors[$item->likeable_id][0]->country; 
     $authors[$item->likeable_id][0]->age; 
    @endif 

@empty 

@endforelse 

最後考慮: 使用這種方法,你會: - 改變你的架構和更新模型 - 你不會使用morphTo, - 你做的1 3次的查詢,而不是,但並不複雜 - 你可以直接使用paginate - 你總是使用id爲輔助查詢(其是良好的性能)

唯一的「陰暗面」正如我說的是,你可能有一些內容你不$books$authors需要的情況下,你是不是從likeable_items調度的ID,但我認爲這是一個合理的交易。