SQLAlchemy:过滤存储在 JSONB 字段的嵌套列表中的值

cro*_*ind 5 python postgresql json sqlalchemy

假设我有一个名为 的模型Item,其中包含一个 JSONB 字段data。其中一条记录存储了以下 JSON 对象:

{
    "name": "hello",
    "nested_object": {
        "nested_name": "nested"
    },
    "nested_list": [
        {
            "nested_key": "one"
        },
        {
            "nested_key": "two"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我可以通过对name字段进行过滤来找到此记录:

Session().query(Item).filter(Item.data["name"] == "hello")
Run Code Online (Sandbox Code Playgroud)

我可以通过同样过滤嵌套对象来找到此记录:

Session().query(Item).filter(Item.data[("nested_object","nested_name")] == "hello")
Run Code Online (Sandbox Code Playgroud)

但是,我正在努力通过过滤存储在嵌套列表中的项目的值来寻找找到此记录的方法。换句话说,如果用户提供了值“一”,我想找到上面的记录,并且我知道要nested_keynested_list.

是否可以使用可用的 SQLAlchemy 过滤器来实现这一点?

Ilj*_*ilä 6

SQLAlchemy 的JSONB类型具有Postgresql 中操作符的contains()方法@>@>运算符用于检查左侧值是否包含顶层的右侧 JSON 路径/值条目。在你的情况下

data @> '{"nested_list": [{"nested_key": "one"}]}'::jsonb
Run Code Online (Sandbox Code Playgroud)

或者在python中

the_value = 'one'

Session().query(Item).filter(Item.data.contains(
    {'nested_list': [{'nested_key': the_value}]}
))
Run Code Online (Sandbox Code Playgroud)

该方法将您的 python 结构转换为适合数据库的 JSON 字符串。

在 Postgresql 12 中,您可以使用JSON 路径函数:

import json

Session().query(Item).\
    filter(func.jsonb_path_exists(
        Item.data,
        '$.nested_list[*].nested_key ? (@ == $val)',
        json.dumps({"val": the_value})))
Run Code Online (Sandbox Code Playgroud)