我有两个模型 Foo
和 Bar
。 Foo
有一个字段 barId
,因此有一个 Bar
对象与之关联。
我可以查询我所有的 Foo
对象并包括它们相关的 Bar
对象(我正在使用带有 sequelize-typescript 的 TypeScript):
Foo.findAll<Foo>({
include: [{ model: Bar }]
});
Bar
对象有一个 JSONB 字段 jsonb_field
with structure
{ 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()
?
最佳答案
使用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 的攻击, 以确保转义或删除所有可能导致问题的字符 ("
,'
,...)
是的,我刚刚回答了我自己的问题。不客气。
关于node.js - 使用 Sequelize.js 和 PostgreSQL 查询关联模型上的 JSONB 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46421054/