Laf 云数据库:用正则表达式对文本字段做模糊查询($regex 实战指南)
【免费下载链接】lafLaf is a vibrant cloud development platform that provides essential tools like cloud functions, databases, and storage solutions. It enables developers to quickly unleash their creativity and bring innovative ideas to life with ease.项目地址: https://gitcode.com/GitHub_Trending/la/laf
本篇基于 Laf 官方文档 使用正则进行模糊查询 展开,讲解如何在 Laf 云数据库(@lafjs/cloud的cloud.mongo.db驱动)中使用正则表达式完成文本字段的模糊查询,包括$regex基础用法、在$in中匹配多个正则、以及$not否定组合;并结合仓库中 database-ql 查询序列化器、已废弃的 RegExp 工具类 与 where 单元测试 剖析正则条件从 JS 语法糖到最终{ $regex, $options }查询语句的底层转换链路。读完本文,你可以直接在云函数中写出正确的正则查询,并理解正则标志位、否定查询与数据库引擎(Mongo / MySQL)之间的适用边界。
一、概述:正则查询在 Laf 云数据库中的位置
Laf 的云数据库通过@lafjs/cloudSDK 暴露 Mongo 风格的数据库驱动。在云函数中通常这样拿到数据库句柄:
import cloud from '@lafjs/cloud' const db = cloud.mongo.db其中cloud.mongo是 SDK 中Cloud类的一个 getter,从源码 packages/cloud-sdk/src/cloud.ts 可以看到它直接返回底层CloudSdkInterface提供的MongoDriverObject(即 Mongo 风格驱动对象),.collection(name)之后得到的集合支持find({ ... })这类标准 Mongo 查询条件对象。
本文要解决的问题是:当需要“名字包含某个字”“姓名以某姓开头”这类文本模糊匹配时,如何用正则表达式(RegExp)表达查询条件。
二、基础用法:用$regex做包含匹配
下面的示例查询users集合中所有名字中包含王的用户(示例完整继承自官方文档):
import cloud from '@lafjs/cloud' const db = cloud.mongo.db export default async function () { const docs = await db.collection('users') .find({ name: { $regex: /王/ } // 正则字面量:名字中包含“王” }) .toArray() console.log(docs) }运行输出:
[ { _id: new ObjectId("65797a86f313010ca6017f6f"), name: '王小波', age: 1000 }, { _id: new ObjectId("65797a86f313010ca6017f6f"), name: '兰陵王', age: 30 } ]要点说明:
$regex操作符的值可以是JS 正则字面量(如/王/),也可以是字符串形式的正则表达式;- 不加
^、$锚点时,/王/表示“任意位置包含”,所以兰陵王也能命中; - 正则标志位(如
i忽略大小写)直接写在字面量后面,例如/abc/i,序列化时会原样带入(见下一节底层实现)。
三、在$in操作符中使用多个正则
当需要匹配“多个正则之一”时,可以把正则数组直接作为$in的值。下面的示例查询所有姓王或陈(即首字为王或陈)的用户:
import cloud from '@lafjs/cloud' const db = cloud.mongo.db export default async function () { const docs = await db.collection('users') .find({ name: { $in: [/^王/, /^陈/] } // 两个正则:以“王”开头 或 以“陈”开头 }) .toArray() console.log(docs) }运行输出:
[ { _id: new ObjectId("65797a86f313010ca6017f6f"), name: '王小波', age: 1000 }, { _id: new ObjectId("65797a86f313010ca6017f6f"), name: '陈奕迅', age: 40 } ]这里的关键是^锚点:/^王/限定“王”必须出现在字符串开头,因此兰陵王虽然含王但不会命中。$in+ 正则数组是“多模式前缀匹配”的简洁写法,避免了显式的$or。
四、$regex与$not组合:否定查询
如果需要查询“不姓王”的用户,可以用$not包裹$regex:
import cloud from '@lafjs/cloud' const db = cloud.mongo.db export default async function () { const docs = await db.collection('users') .find({ name: { $not: { $regex: /^王/ } } // 名字不以“王”开头 }) .toArray() console.log(docs) }运行输出:
[ { _id: new ObjectId("65797a86f313010ca6017f6f"), name: '陈奕迅', age: 40 }, { _id: new ObjectId("65797a86f313010ca6017f6f"), name: '兰陵王', age: 30 } ]注意输出中兰陵王仍在结果里——因为$not否定的是/^王/(以“王”开头),而兰陵王只是“包含”王而非“以王开头”。编写否定查询时务必把锚点写清楚,否则语义会出乎意料。
五、底层实现:JS 正则如何被序列化为$regex/$options
上面的查询之所以可以直接写/^王/这样的字面量,是因为 Laf 的查询条件序列化器database-ql会自动把原生RegExp对象编码为 Mongo 查询语法。核心逻辑在 packages/database-ql/src/serializer/query.ts:
encodeRegExp(query: RegExp) { return { $regex: query.source, // 取正则的 pattern 部分(去掉 / 与标志位) $options: query.flags, // 取标志位,如 i、g、m } }也就是说,你在代码里写的/^王/i最终会变成查询文档{ $regex: '^王', $options: 'i' }发给数据库引擎执行。source与flags都是 JSRegExp实例的标准属性,因此正则的所有标志位(i忽略大小写、m多行等)都会被完整保留。
对于第四节的否定写法,序列化器在逻辑命令分支中有专门处理(同文件):当$not的操作数本身是一个RegExp(通过isRegExp判断)时,会调用encodeRegExp生成{ fieldName: { $not: { $regex, $options } } }结构,再与普通查询条件合并。这与 MongoDB 官方$not的语义一致。
该转换链路有单元测试覆盖,见 packages/database-ql/tests/units/get/where.test.js 中的where() with RegExp should be ok用例:用例同时覆盖了字符串写法db.RegExp({ regexp: '^abc.*$' })、原生new RegExp('^abc.*$', 'i')以及正则字面量,断言它们最终都序列化为{ $regex: '^abc.*$', $options: ... }形式的查询条件。
六、注意:旧的db.RegExp(...)构造方式已废弃
在早期版本的 SDK 中,正则需要通过db.RegExp({ regexp, options })构造。从源码 packages/database-ql/src/regexp/index.ts 可以看到,该RegExp类及其构造函数RegExpConstructor均已标注@deprecated,注释明确提示:“use js nativeRegExpinstead”(改用 JS 原生RegExp)。
因此新代码推荐直接使用正则字面量或new RegExp(pattern, flags),它们都会被序列化器原生识别,无需经过废弃的包装类:
// 推荐 find({ name: { $regex: /^王/i } }) find({ name: { $regex: new RegExp('^王', 'i') } }) // 已废弃,仅兼容旧代码 find({ name: db.RegExp({ regexp: '^王', options: 'i' }) })七、适用边界:Mongo 驱动 vs MySQL 引擎
本文所有示例都基于cloud.mongo.db(Mongo 风格驱动)。需要注意 Laf 的数据库代理层同时支持 Mongo 与 MySQL 两种引擎:从 packages/database-proxy/src/accessor/sql_builder.ts 的操作符映射表看,SQL 路径支持的查询操作符包括=、<>、>、>=、<、<=、in、not in,以及 SQL 专用的$like(见 packages/database-proxy/src/types.ts 中LIKE: '$like' // only for SQL query的注释),映射表中并没有$regex分支。
由此可以推断:
$regex正则模糊查询适用于Mongo 引擎 /cloud.mongo驱动场景,本文所有示例均以此为前提;- 若查询目标数据库由 MySQL 引擎承载,模糊匹配应使用 SQL 语义的
$like操作符(%、_通配),而非正则语法; - 编写跨引擎的代码时,建议先确认目标集合实际绑定的数据库类型,再选择等价的模糊匹配方式。
八、常用正则速查(结合本文示例)
| 需求 | 查询条件 | 说明 |
|---|---|---|
| 包含“王” | name: { $regex: /王/ } | 任意位置匹配 |
| 以“王”开头 | name: { $regex: /^王/ } | ^锚定开头 |
| 以“波”结尾 | name: { $regex: /波$/ } | $锚定结尾 |
| 姓“王”或“陈” | name: { $in: [/^王/, /^陈/] } | 多正则之一命中 |
| 不姓“王” | name: { $not: { $regex: /^王/ } } | 否定前缀匹配 |
| 忽略大小写 | name: { $regex: /^wang/i } | i标志位随flags序列化 |
正则语法本身遵循 JavaScript 标准(ECMAScript RegExp),标志位如i(忽略大小写)、g(全局)、m(多行)等均可通过flags原样传给引擎;编写复杂模式时可自行查阅 MDN 的正则表达式参考或 MongoDB 官方$regex文档。
小结
- Laf 云数据库中,文本模糊查询直接使用 JS 原生正则:
$regex: /pattern/flags,序列化器会自动转换为{ $regex, $options }查询语句(序列化实现); $in可接收正则数组,实现“多个前缀/模式任一命中”的简洁写法;$not包裹$regex实现否定查询,注意锚点语义;- 旧版
db.RegExp({ regexp, options })构造方式已标记废弃,新代码统一使用原生RegExp; $regex面向 Mongo 引擎与cloud.mongo驱动;MySQL 引擎的模糊匹配使用$like操作符,编写查询前先确认目标数据库类型;- 更多云数据库查询语法(比较、逻辑操作符等)可继续查阅 docs/zh/cloud-database/query/ 目录及 云数据库总览。
【免费下载链接】lafLaf is a vibrant cloud development platform that provides essential tools like cloud functions, databases, and storage solutions. It enables developers to quickly unleash their creativity and bring innovative ideas to life with ease.项目地址: https://gitcode.com/GitHub_Trending/la/laf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考