基于单个字符串的 Postgres JSON 列表对象上的 Flask SQLAlchemy 过滤器

Flask SQLAlchemy Filter On A Postgres JSON List Object Based on a Single String

我有一个名为测试的模型。名为 alias 的字段是一个 JSON 字段(实际上是一个列表)并且具有 ["a", "b"]["d", "e"] 等值。

class Testing(db.Model):
    __tablename__ = 'testing'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(25))
    alias = db.Column(JSON)

    def __init__(self, name, alias):
        self.name = name
        self.alias = alias

在我的 flask 视图中,我获取了一个 url 参数,我想用它来过滤 Testing 以获取参数值在 alias json 列表中的所有 Testing 对象.因此,例如,如果 url_param_value="a" 我想要 "a"alias 中的所有测试对象。因此,["a", "b"]alias 值在此示例中将成为命中。

这是我的方法,但它不起作用,我认为它与序列化有关。

Testing.query.filter(Testing.alias.contains(url_param_val)).all()

我收到以下错误

NotImplementedError: Operator 'contains' is not supported on this expression

name字段是JSON类型,不是数组类型。 JSON 列没有 contains 方法,即使您恰好存储数组数据(数据库怎么知道?)

在 Postgres 中,您可以使用 json_array_elements 将 JSON 数组扩展为一组 JSON 值;这将 return 每个元素一行:

select id, json_array_elements(alias) as val from testing;

   id    |         val
---------+--------------------
 1       | "a"
 2       | "b"

您可以将其用作 select 包含匹配值的记录的子查询:

select t.id, t.name, t.alias, cast(q.val as varchar)
from testing t, (
    select id, json_array_elements(alias) as val
    from testing
) q
where q.id=t.id and cast(q.val as varchar) = '"a"';

在 SQLAlchemy 语法中:

subq = session.query(
    Testing.id,
    func.json_array_elements(Testing.alias).label("val")
).subquery()
q = session.query(Testing).filter(
    cast(subq.c.val, sa.Unicode) == '"a"',
    subq.c.id == Testing.id)

警告:这对于大表来说效率非常低;您最好修复类型以匹配您的数据,然后创建适当的索引。