Laravel 5.3 - 在一个查询中提取多态表的数据?

问题描述:

使用多态关系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个表格的模式吗? –

你可以从你的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; 
    } 
} 

如果你愿意改变架构和具有大于一个查询可能的解决办法是:

更新模式:

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,但我认为这是一个合理的交易。