Laravel Eloquent 搜索小技巧
57

file

当我们的应用程序不是很复杂时(例如在开始时),应用小型手工解决方案就足够了。 数据库搜索也是如此。 没有必要立即拉入第三方扩展包。 大多数情况下,我们可以使用一些简单的技术在 Eloquent 中执行搜索。

热身

搜索是任何应用程序的重要组成部分。 良好的界面有助于用户检索所需的信息。 因此,在前端和后端都需要一个好的解决方案。 在这篇文章中,我们没有涉及任何UI或前端相关主题。 我们已经发布了一篇关于该文章的文章

所以现在,我们只讨论 MySQL 和 Eloquent。

简单的 Where 子句

可以使用 where 子句来将给定值与特定列进行比较,这没啥新鲜的。

<?php

$results = Post::where('title', 'foo')->get();

但更进一步,我们也可以传递一个数组来比较多个列。 这和 && 运算符的工作原理差不多,我们取得的返回结果是满足所有条件的:

<?php

$results = Post::where([
    ['title', '=', 'foo'],
    ['published', '=', true],
])->get();

只要想做,我们也可以构建类似 || 运算符工作原理的查询语句,只要在查询构建器上加一个 orWhere() 方法就行。

<?php

$results = Post::where('title', 'foo')->orWhere('description', 'foo')->get();

有很多种组合你 where 子句的可能性,我强烈建议你看看 相关文档

使用 Like 关键字

稍微深入一点点, 我们一起来看一下 MySQL 的 LIKE 关键字。 这个的重点在于,比起常规的相等检查,它的灵活性更强大。我们可以使用通配符,使得事情变得更加有意思。使用 % 字符作为通配符:

<?php

// 设置变量
$keyword = 'foo';

// 以 'foo' 开头,随便什么结尾都可以
$results = Post::where('title', 'like', "{$keyword}%")->get();

// 以 'foo' 结尾, 随便什么开头都可以
$results = Post::where('title', 'like', "%{$keyword}")->get();

// 包含 'foo'
$results = Post::where('title', 'like', "%{$keyword}%")->get();

如你所见,这灵活多了。我们可以检查一个值是否以特定字符串开头或结尾,或者是否包含这个字符串。想象一下,你不记得整个式子,只记得一部分,但你输入了几个单词后,仍然能得到想要的结果!

有个重要提示:可能你使用到了一个以 _ci 结尾的排序规则。这表明它是大小写不敏感的。不管你输入 FOO,Foo,fOO,等等中的哪一个,得到的结果都是相同的。

当然了,你也可以使用你在文档中发现的其他 where 子句或者组合!

JSON 列的查询

JSON 类型带来了巨大的灵活性,这非常棒! 由于对 JSON 良好的支持,我们也可以使用 Eloquent 轻松的搞定对 JSON 列的查询。但是在深入研究之前,有一个重要的注意事项:即使你设置了个大小写不敏感的排序规则,JSON 列依然是大小写敏感的。

假如没有这个问题,我们可以这么做:

<?php

$results = Post::where('meta->description', 'like', '%foo%')->get();

没啥特别的,对吗? 但如果当它大小写不敏感的时候我们又必须处理它,会怎么样呢?这就是了解 whereRaw() 表达式的最佳场景。我们先看代码后解释:

<?php

$keyword = 'foo';
$results = Post::whereRaw('lower(meta->"$.description") like lower(?)', ["%{$foo}%"]);

你应该也注意到了一些东西。首先就是语法,没有上面的那么简洁了。 这是因为我们传的是一个原生表达式而不是封装的。

那还有别的什么吗?注意第二个 lower 函数。我们称之为参数绑定(parameter binding)。这是个保护你不被易受攻击的值伤害的不错方式。如你所见,我们传递了一个数组作为第二个参数。数组第一项代表了第一个绑定,第二项代表第二个绑定,以此类推。这就是原生表达式的工作原理。

接下来进入真正的重点:我们使用 lower() 函数是因为通过这样做,我们能够确保 JSON 列不区分大小写。转换给定值并以小写形式保存起来,然后再进行比较。虽然有点小滑头,但是堪称完美!

It "Sounds Like" ...

现在,把注意力转移到今天要科普的最后一个东西上。假如用户把表达式输错了咋办?查一下数据库里是否有跟这个错误的表达式相似的记录是个不错的解决办法。 这里可以使用 LIKE 关键字,但是没必要,因为有 SOUNDS LIKE 关键字。

我们不会科普它的工作原理,但如果你有兴趣的话,可以看看 这里 来深入一下下。它会给你科普你想知道的。 现在,一起来看看怎么使用它:

<?php

$results = Post::where('title', 'sounds like', 'mistpyed')->get();

对于 MySQL sounds like 的支持,是在 Laravel 5.6.8 中添加的。可以看看 更新日志.

在幕后,它运行了一套算法来计算值的相似度。幸运的是,我们根本不需要关心这个。我们要做的只是把值传给 where 子句,然后等待结果就可以了。 我们获得了与给定表达式相似的结果,而不仅是那些完全一样的或者包含它的。

总结

诚如我们所见,Laravel 提供了一个很好的方式来执行容易实现,而灵活的解决方案。我们可以结合 where 子句,我们可以在需要时使用原生表达式,也可以使用一些不为大家熟知的关键字。所有这一切都是默认支持的,多么简洁啊!
如果你使用其它方法,请大方地在评论区告诉我们!


Practice makes perfect.

原文地址:https://pineco.de/basic-eloquent-search-...

译文地址:https://laravel-china.org/topics/9776/la...

本帖已被设为精华帖!
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 5

老铁们,『墙裂』真的不是错别字,你们搜一下『墙裂安利』就知道了,真的,不骗你们~

5个月前
Destiny

sounds like 很赞 :+1:

5个月前

sounds like 学到了

5个月前

@JiaZombie 墙裂安利的文档链接是404,请问可以更改下吗

4个月前

@4pmyyy 已更新

4个月前

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!