我有一个文章和标签表。每篇文章可以有多个标签。我想获取一篇文章的相关文章,并根据常见标签对结果进行排序。
// Tag Model
class Tag extends Model
{
public function posts()
{
return $this->morphedByMany(Article::class, 'taggable');
}
}
// Article Model
class Article extends Model
{
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
我使用此代码获取相关文章,但我不知道如何基于更常见的标签对结果进行排序。
// And i
$relatedArticle = Article::whereHas('tags', function($query) use ($article){
$query->whereIn('name', $article->tags->pluck('name'));
})->where('id', '!=', $article->id)->take(10)->get();
答案 0 :(得分:1)
在SQL中,所需的信息将通过以下方式检索(我不知道关联表的名称或外键和主键,因此如有必要,请进行更改):
SELECT articles.*,
(
SELECT COUNT(tags.id)
FROM tags
JOIN articles_tags at ON tags.id = at.tag_id
WHERE tags.name in ('A', 'B', 'C') /* acquired from $article->tags->pluck('name') */
AND at.article_id = a.id
) as tags_in_common
FROM articles a
WHERE articles.id != {$id}
AND tags_in_common >= 1
ORDER BY tags_in_common DESC
LIMIT 10;
现在,使用queryBuilder,我们必须变得有点脏,但是看起来可能像这样:
//Fetches pairs: [article_id, numberInCommon]
$tagsInCommon = DB::table('tags')
join('articles_tags', 'tags.id', '=', 'articles_tags.tag_id')
->select('articles_tags.article_id', DB::raw('COUNT(*) as numberInCommon'))
->whereIn('tags.name', $article->tags->pluck('name'))
->groupBy('articles_tags.article_id')
$relatedArticle = Article::
->joinSub($tagsInCommon, 'tags_in_common', function($join){
$join->on('id', '=', 'tags_in_common.article_id')
})
->where('id', '!=', $article->id)
->orderBy('tags_in_common.numberInCommon', 'desc')
->take(10)
->get();