如何在 Sequelize Postgres 中使用小写函数
Posted
技术标签:
【中文标题】如何在 Sequelize Postgres 中使用小写函数【英文标题】:How to use Lowercase function in Sequelize Postgres 【发布时间】:2016-04-17 16:45:16 【问题描述】:我正在尝试使用小写函数在 Sequelize 中进行字符串搜索。 我设法使用ilike来做到这一点。 我的问题是在这种情况下如何使用小写函数?
使用ilike的findAll
如下:
Db.models.Person.findAll(where: firstName: $ilike: `somename`);
如何将其更改为lower(firstname) = lower('somename');
【问题讨论】:
不知道这是否适用于您,但在我的情况下,我尝试在 C# linq 中使用 unaccent 函数并且无法使其工作,最后只需创建一个新列u_column
并使用 postgres 函数填充。不漂亮,但工作。
【参考方案1】:
你可以在 where 子句中使用原生函数:
Db.models.Person.findAll(
where: sequelize.where(
sequelize.fn('lower', sequelize.col('firstname')),
sequelize.fn('lower', 'somename')
)
);
这将转化为
select * from person where lower(firstname) = lower('somename');
【讨论】:
使用这种方式,当我需要搜索多个参数时,我应该怎么做。例如:姓氏和电话号码。其中 lastName 是类似于 firstName 的字段类型,phoneNumber 是存储数字的字段。 您只需像往常一样将它们添加到您的where:
对象中。 where: sequelize.where(sequelize.fn('lower', sequelize.col('firstname')), sequelize.fn('lower', 'somename')), phoneNumber: 8435551212
@Ben:这对我不起作用,我建议:where: phoneNumber: '8435551212', $col: sequelize.where(sequelize.fn('lower', sequelize.col('firstname')), sequelize.fn('lower', 'somename'))
【参考方案2】:
PostgreSQL 通常使用区分大小写的排序规则。这意味着每列中出现的数据都会与您的查询进行逐字比较。
您有多种选择:
1.按照 Ben 的回答,将包装列和数据库包装在 sequelize.fn('lower')
调用中。
优点:没有数据库更改。
缺点:您需要记住对每个查询都使用它。放弃索引(除非您已经创建了functional index)并按顺序扫描表,从而导致查找大型表的速度变慢。相当冗长的代码。
2。使用 ILIKE,不区分大小写地匹配模式
要准确查找名称:
Db.models.Person.findAll(where: firstName: $iLike: 'name');
要查找可能包含在任意字符中的片段:
Db.models.Person.findAll(where: firstName: $iLike: '%name%');
优点:容易记住。没有 Sequelize 函数包装器 - 它是一个内置运算符,因此语法更整洁。不需要特殊的索引或数据库更改。
缺点:速度慢,除非你开始弄乱pg_trgm 之类的扩展名
3.使用 citext 类型定义文本列,隐式比较小写
将您的列类型定义为“citext”(而不是text
或character varying
)具有与此相同的实际效果:
select * from people where name = 'DAVID'
到这个...
select * from people where LOWER(name) = LOWER('DAVID')
PostgreSQL 文档显示了如何使用 citext 类型创建表的示例:
CREATE TABLE users (
nick CITEXT PRIMARY KEY,
pass TEXT NOT NULL
);
INSERT INTO users VALUES ( 'larry', md5(random()::text) );
INSERT INTO users VALUES ( 'Tom', md5(random()::text) );
INSERT INTO users VALUES ( 'Damian', md5(random()::text) );
INSERT INTO users VALUES ( 'NEAL', md5(random()::text) );
INSERT INTO users VALUES ( 'Bjørn', md5(random()::text) );
SELECT * FROM users WHERE nick = 'Larry';
TL;DR 基本上将您的“文本”列换成“citext”。
citext 模块与 PostgreSQL 8.4 捆绑在一起,因此无需安装任何扩展。但是您确实需要在使用以下 SQL 的每个数据库上启用它:
CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;
然后在您的 Sequelize 定义中,定义一个 type
属性:
// Assuming `Conn` is a new Sequelize instance
const Person = Conn.define('person',
firstName:
allowNull: false,
type: 'citext' // <-- this is the only change
);
那么您对该列的搜索将始终使用常规 where =
查询不区分大小写
优点:无需将您的查询包装在丑陋的 sequelize.fn
调用中。无需记住显式小写。区域设置感知,因此适用于所有字符集。
缺点:您需要记住在首次定义表时在 Sequelize 定义中使用它。始终处于激活状态 - 您需要知道在定义表格时要进行不区分大小写的搜索。
【讨论】:
我通过以下迁移完成了第三个解决方案。可能对其他人有用:module.exports = up: function (queryInterface, Sequelize) queryInterface.sequelize.query('CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;'); queryInterface.sequelize.query('CREATE TABLE mytable(email CITEXT PRIMARY KEY NOT NULL, password TEXT NOT NULL);'); ,向下:函数(queryInterface,Sequelize)queryInterface.dropTable('mytable'); ; Re #2:如果name
中的特殊字符来自用户,则可能需要额外的代码来转义它。
我想知道一般人会如何设计不区分大小写的搜索,但有时仍会选择区分大小写的匹配。我们是否需要在应用程序代码中进行第二次传递以应用区分大小写,或者是否有一个 SQL 运算符表示“这次,尊重大小写,即使这个字段是 citext”?
CITEXT 恕我直言的另一个缺点是它不能与字段的最大长度组合!此外,在使用 dockerized psql 数据库时,正确设置它非常麻烦,但这可能是个人的事情。以上是关于如何在 Sequelize Postgres 中使用小写函数的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Sequelize Postgres 中使用小写函数
如何在 NestJs 框架中使用 postgres 和 sequelize 正确定义 DTO 对象
Sequelize Postgres - 如何使用 ON CONFLICT 来实现独特的?
用户如何使用 sequelize postgres nodejs 互相喜欢和不同?