laravel下 如何更优雅的实现这个数据查询需求

背景

laravel 版本

5.4

数据表关系

res 资源
tag 标签

资源 和 标签是多对多关系,所以有中间表 res_tag。

问题

我希望取出一个资源列表,要求如下:

  • 最新的5条
  • tag.id in (1,3,5)

笨方法

我用查询构造器,实现这样的SQL语句。

SELECT
    *
FROM
    res
LEFT JOIN res_tag ON res_tag.res_id = res.id
WHERE
    res_tag.tag_id IN (1, 3, 5)

期望答案

laravel 中是否有更优雅的实现方法。

我对更优雅的定义:比如利用ORM的 “关联” 是否能实现?

20171205,追问

非常感谢 @nopainnogain 的解答,我做了如下修改。

代码

knowledge 就是 tag(上文我为了叙述问题,做了简化)

$knowledge = new Knowledge();
$res = $knowledge->res()
    ->whereIn('knowledge_id', $knowledge_ids)
    ->orderBy('created_at', 'desc')
    ->limit(5)->get();

SQL

实际执行的SQL语句,程序自动添加了 knowledge_res.knowledge_id IS NULL 这个查询条件,导致查不出任何数据。(去掉此查询条件,结果能满足需求

SELECT
 * FROM
    `res`
INNER JOIN `knowledge_res` ON `res`.`id` = `knowledge_res`.`res_id`
WHERE
    `knowledge_res`.`knowledge_id` IS NULL
AND `knowledge_id` IN (
    164,
    165,
    166,
    167,
    168,
    169,
    170
)
AND `res`.`deleted_at` IS NULL
ORDER BY
    `created_at` DESC
LIMIT 5

另外,有一事疑惑

回答中代码:资源Model::query()->tags()

生成的SQL: select * from tag inner 资源 ... 这样取出的资源是以 tag 为主的,我希望是资源列表

所以我改为:tagModel::query()->资源()

生成的SQL:select * from 资源 inner join tag ... 也就是上文提供的SQL。

不知道是解答时手误还是我其他环节出了问题。

阅读 2.1k
1 个回答

你这是标准的多对多模型关联
在你的资源Model里定义个新方法:

public function tags()
{
    return $this->belongsToMany('标签Model');
}

然后:

资源Model::query()
->tags()
->whereIn('res_id',[1,3,5])
->orderBy('create_time','desc')
->limit(5)
->get();

2017-12-5
试试:

ResModel::whereHas('knowledge', function ($query) use ($knowledge_ids) {
    $query->whereIn('knowledge_id', $knowledge_ids);
})
->orderBy('created_at', 'desc')
->limit(5)
->get();
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题