SQLAlchemy has_any()
SQLAlchemy has_any()
我无法使用 SQLAlchemy 的 has_any()
函数。我只是想在 jsonb 列中包含的列表中过滤我的结果:
db.session.query(models.Record.id).\
filter(models.Record.record_metadata["teams"].has_any(team_ids))
models.Record.record_metadata["teams"]
是 jsonb 列 (record_metadata
) 中的一个 id 列表,我想与 team_ids
进行比较,它也是一个 id 列表
生成的查询是:
SELECT record.id AS record_id
FROM record
WHERE ((record.record_metadata -> 'teams')) ?| '["id1", "id2"]';
这给出了错误
DataError: (psycopg2.DataError) malformed array literal: "["id1", "id2"]"
LINE 3: WHERE ((record.record_metadata -> 'teams')) ?| '["id1", "id2"]'
^
DETAIL: "[" must introduce explicitly-specified array dimensions.
但是关于 Postgres 官方文档中的 Table 9.44. Additional jsonb Operators,|?
运算符后面应该跟一个 array[]
确实,当我手动编写查询时:
SELECT record.id AS record_id
FROM record
WHERE ((record.record_metadata -> 'teams')) ?| array['id1', 'id2'];
它工作得很好。
SQLAlchemy's documentation关于这个功能很差,我找不到任何例子。
难道我这个功能做错了什么?我应该为这种情况使用其他东西吗?还是has_any()
坏了?
编辑:
SELECT record.id AS record_id
FROM record
WHERE ((record.record_metadata -> 'teams')) ?| '{"id1", "id2"}';
也很好用,我发现 has_any()
也接受字符串。
所以这是一个(非常)讨厌的修复,但是如果我用所需的 ID 格式化字符串:
db.session.query(models.Record.id).\
filter(models.Record.record_metadata["teams"].has_any(
str(team_ids).
replace('[', '{').
replace(']', '}').
replace('\'', '\"')))
有效...
似乎默认情况下传递的值是 JSON 编码的,如果它是 list
或 dict
。您可以通过显式传递 array
literal:
来解决这个问题
In [15]: from sqlalchemy.dialects.postgresql import array
In [16]: session.query(Foo).\
...: filter(Foo.data['test'].has_any(array(['1', '2']))).all()
2018-06-18 09:07:20,780 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-06-18 09:07:20,780 INFO sqlalchemy.engine.base.Engine SELECT foo.id AS foo_id, foo.data AS foo_data
FROM foo
WHERE ((foo.data -> %(data_1)s)) ?| ARRAY[%(param_1)s, %(param_2)s]
2018-06-18 09:07:20,781 INFO sqlalchemy.engine.base.Engine {'data_1': 'test', 'param_1': '1', 'param_2': '2'}
Out[16]: []
这样您就不需要从 Python list
的字符串表示中手动格式化数组文字,这可能很容易出错。
错误本身是 Postgresql 试图将传递的文字(包含 JSON)解析为数组的结果。如错误所述,text representation of an array 可能以指定数组下标范围的维度修饰开头:
'[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[]
我无法使用 SQLAlchemy 的 has_any()
函数。我只是想在 jsonb 列中包含的列表中过滤我的结果:
db.session.query(models.Record.id).\
filter(models.Record.record_metadata["teams"].has_any(team_ids))
models.Record.record_metadata["teams"]
是 jsonb 列 (record_metadata
) 中的一个 id 列表,我想与 team_ids
进行比较,它也是一个 id 列表
生成的查询是:
SELECT record.id AS record_id
FROM record
WHERE ((record.record_metadata -> 'teams')) ?| '["id1", "id2"]';
这给出了错误
DataError: (psycopg2.DataError) malformed array literal: "["id1", "id2"]"
LINE 3: WHERE ((record.record_metadata -> 'teams')) ?| '["id1", "id2"]'
^
DETAIL: "[" must introduce explicitly-specified array dimensions.
但是关于 Postgres 官方文档中的 Table 9.44. Additional jsonb Operators,|?
运算符后面应该跟一个 array[]
确实,当我手动编写查询时:
SELECT record.id AS record_id
FROM record
WHERE ((record.record_metadata -> 'teams')) ?| array['id1', 'id2'];
它工作得很好。
SQLAlchemy's documentation关于这个功能很差,我找不到任何例子。
难道我这个功能做错了什么?我应该为这种情况使用其他东西吗?还是has_any()
坏了?
编辑:
SELECT record.id AS record_id
FROM record
WHERE ((record.record_metadata -> 'teams')) ?| '{"id1", "id2"}';
也很好用,我发现 has_any()
也接受字符串。
所以这是一个(非常)讨厌的修复,但是如果我用所需的 ID 格式化字符串:
db.session.query(models.Record.id).\
filter(models.Record.record_metadata["teams"].has_any(
str(team_ids).
replace('[', '{').
replace(']', '}').
replace('\'', '\"')))
有效...
似乎默认情况下传递的值是 JSON 编码的,如果它是 list
或 dict
。您可以通过显式传递 array
literal:
In [15]: from sqlalchemy.dialects.postgresql import array
In [16]: session.query(Foo).\
...: filter(Foo.data['test'].has_any(array(['1', '2']))).all()
2018-06-18 09:07:20,780 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-06-18 09:07:20,780 INFO sqlalchemy.engine.base.Engine SELECT foo.id AS foo_id, foo.data AS foo_data
FROM foo
WHERE ((foo.data -> %(data_1)s)) ?| ARRAY[%(param_1)s, %(param_2)s]
2018-06-18 09:07:20,781 INFO sqlalchemy.engine.base.Engine {'data_1': 'test', 'param_1': '1', 'param_2': '2'}
Out[16]: []
这样您就不需要从 Python list
的字符串表示中手动格式化数组文字,这可能很容易出错。
错误本身是 Postgresql 试图将传递的文字(包含 JSON)解析为数组的结果。如错误所述,text representation of an array 可能以指定数组下标范围的维度修饰开头:
'[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[]