【问题标题】:How to use Lowercase function in Sequelize Postgres如何在 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 函数填充。不漂亮,但工作。

标签: node.js postgresql sequelize.js


【解决方案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 数据库时,正确设置它非常麻烦,但这可能是个人的事情。
猜你喜欢
  • 1970-01-01
  • 2019-03-10
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
  • 2016-04-21
相关资源
最近更新 更多