【发布时间】:2021-06-05 09:15:19
【问题描述】:
你好 SO 的伟大人物!
希望大家天天开心,身体健康
注意:我不擅长 SQL
抱歉英语不好,但我会尽力解释我的问题
我在我的应用程序中使用 Laravel v8.x,在设置模型关系、事件、队列等之后,现在我正在为 SQL 工作
ATM,我有 2 个型号,
UserPost
关系:
-
UserhasManyPost -
UserbelongsToManyUser(块) -
UserbelongsToManyUser(关注) -
Post属于User
数据库:
User 的 5 条记录
Block 的 2 条记录
Post 的 3 条记录
表格:(使用faker)
users
[
{ id: 1, name: 'Jonathan Beatrice', username: 'kiana.fay', ... },
{ id: 2, name: 'Lacey Kirlin', username: 'kenna.turner', ... },
{ id: 3, name: 'Alexander Schiller', username: 'cassandra95', ... },
{ id: 4, name: 'Daniel Wickozky', username: 'nkoepp', ... },
{ id: 5, name: 'Maymie Lehner', username: 'frami.felton', ... }
]
block
[
{ id: 1, by_id: 1, to_id: 2 }, // User #1 block user #2
{ id: 2, by_id: 4, to_id: 1 } // User #4 block user #1
]
posts
[
{ id: 1, user_id: 2, body: 'Test post', ... },
{ id: 2, user_id: 5, body: 'Lorem ipsum dolor sit amet ...', ... },
{ id: 3, user_id: 4, body: 'ABCD festival soon! ...', ... },
]
一切顺利
现在我想实现搜索系统,我有一个问题,因为我不擅长SQL
这是我的代码
SearchController.php
use ...;
use ...;
...
public function posts(Request $request)
{
// For testing purpose
$user = User::with(['userBlocks', 'blocksUser'])->find(1);
// Get all id of user that $user block
// return [2]
$user_blocks = $user->userBlocks->pluck('pivot')->pluck('to_id')->toArray();
// Get all id of user that block $user
// return [4]
$blocks_user = $user->blocksUser->pluck('pivot')->pluck('by_id')->toArray();
// Merge all ids above (must be unique())
// return [2, 4]
$blocks = array_merge($user_blocks, $blocks_user);
// .../search?q=xxx
$query = $request->query('q');
$sql = Post::query();
// Search for posts that has `posts`.`body` LIKE ? ($query)
$sql->where('body', 'LIKE', "%$query%");
// This is where I got confused
$sql->orWhereHas('user', function ($post_user) use ($blocks, $query) {
$post_user
->whereNotIn('id', $blocks) // Exclude posts that has user and their id not in (x, x, x, x, ... ; $block variable above)
->where('name', 'LIKE', "%$query%") // Find user that has name LIKE ? ($query)
->orWhere('username', 'LIKE', "%$query%"); // or Find user that has username LIKE ? ($query)
});
$sql->orderBy('created_at', 'DESC');
$sql->with(['user']);
$posts = $sql->simplePaginate(10, ['*'], 'p');
return $posts;
}
我运行代码,.../search?q=e
注意:
- 所有
users的名称中都有字母E - 而且所有
posts的正文中都有字母E - 我们(作为用户 #1)屏蔽用户 #2,用户 #4 屏蔽我们(用户 #1)
结果:控制器返回所有帖子
这是我使用DB::enableQueryLog()和DB::getQueryLog()时的查询
SELECT
*
FROM
`posts`
WHERE `body` LIKE ?
AND EXISTS
(SELECT
*
FROM
`users`
WHERE `posts`.`user_id` = `users`.`id`
AND (
`id` NOT IN (?)
AND `username` LIKE ?
OR `name` LIKE ?
))
ORDER BY `created_at` ASC
LIMIT 11 OFFSET 0
目标:搜索所有有 body LIKE 的帖子,或者有用户的帖子;用户名 LIKE ?或名称 LIKE ? (但也要排除我们屏蔽的用户和屏蔽我们的用户
提前致谢
如果有任何不清楚的解释,我会尽快编辑它
【问题讨论】:
-
您也许可以使用
whereDoesntHave(docs),但看到它是如何自加入可能会很棘手 -
如果我尝试理解
whereDoesntHave方法,它将获取所有没有用户的帖子?同时,帖子必须是belongsTo用户