如何在 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”(而不是textcharacter 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 互相喜欢和不同?

NodeJS/Sequelize/MySQL - 为啥需要 postgres 依赖项?

Sequelize w/Postgres 测试异步错误