使用 Sequelize.js 和 PostgreSQL 在关联模型上查询 JSONB 字段

Posted

技术标签:

【中文标题】使用 Sequelize.js 和 PostgreSQL 在关联模型上查询 JSONB 字段【英文标题】:Querying JSONB field on a associated model with Sequelize.js and PostgreSQL 【发布时间】:2018-03-07 08:36:23 【问题描述】:

我有两个模型 FooBarFoo 有一个字段 barId,因此有一个 Bar 对象与之关联。 我可以查询我所有的 Foo 对象并包含它们关联的 Bar 对象(我正在使用带有 sequelize-typescript 的 TypeScript):

Foo.findAll<Foo>(
  include: [ model: Bar ]
);

Bar 对象有一个 JSONB 字段 jsonb_field 具有结构

 inner_field1: 'some text', inner_field2: 'some more text' 

我可以像这样查询Bar 对象并按inner_field1 过滤:

Bar.findAll<Bar>(
  where:  'jsonb_field':  inner_field1: 'text to find'  
);

这会产生以下 SQL 查询:

SELECT ... FROM "Bar" AS "Bar" 
WHERE ("Bar"."jsonb_field"#>>'inner_field1') = 'text to find'

到目前为止一切顺利。现在让我们尝试查询Foo 对象,包括Bar 对象并按inner_field1 过滤:

Foo.findAll<Foo>(
  where:  '$bar.jsonb_field$':  inner_field1: 'text to find'  ,
  include: [ model: Bar ]
);

现在这会引发异常:

Error: Invalid value [object Object]
    at Object.escape (project_root\node_modules\sequelize\lib\sql-string.js:50:11)
    at Object.escape (project_root\node_modules\sequelize\lib\dialects\abstract\query-generator.js:917:22)
    at Object.whereItemQuery (project_root\node_modules\sequelize\lib\dialects\abstract\query-generator.js:2095:41)
    at _.forOwn (project_root\node_modules\sequelize\lib\dialects\abstract\query-generator.js:1937:25)
    ...

作为记录,我正确地包含了 Bar 对象,因为我可以按其他非 JSONB 属性进行过滤:

Foo.findAll<Foo>(
  where:  '$bar.number_field$': 5 ,
  include: [ model: Bar ]
);

据我所知,问题在于 Sequelize 不知道 jsonb_field 的类型,因此在将对象传递给 where 查询时会引发错误。

有没有办法解决这个错误,可能使用sequelize.literal()sequelize.json()

【问题讨论】:

【参考方案1】:

使用sequelize.cast$contains 运算符:

Foo.findAll<Foo>(
  where:  '$bar.jsonb_field$': 
    $contains: sequelize.cast(' "inner_field1": "text to find" ', 'jsonb')
  ,
  include: [ model: Bar ]
);

或者按照您的建议使用sequelize.literal

Foo.findAll<Foo>(
  where:  '$bar.jsonb_field$': 
    $contains: sequelize.literal(`' "inner_field1": "text to find" '::json`)
  ,
  include: [ model: Bar ]
);

这两种解决方案都容易受到SQL Injections 的攻击,以确保转义或删除所有可能导致问题的字符(",',...)

是的,我刚刚回答了我自己的问题。不客气。

【讨论】:

如果您需要检查是否相等,它将起作用。但是,例如,在 [Op.Like] 的情况下,它没有帮助。

以上是关于使用 Sequelize.js 和 PostgreSQL 在关联模型上查询 JSONB 字段的主要内容,如果未能解决你的问题,请参考以下文章

使用 Node JS + Sequelize JS 时出错

Sequelize.js 外键

Sequelize.js 插入具有一对多关系的模型

即使 paranoid 设置为 true,Sequelize.js 仍会删除表行

使用 Sequelize.js 进入包含模型

使用 Sequelize.js 时在哪里定义关联/关系?