Фильтр Sqlalchemy вложенный JSONB в массивах - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть поле Postgres JSONB с несколькими вложенными массивами и другими объектами.

from sqlalchemy.dialects.postgresql import JSONB


class Family(db.Model):
   meta = db.Column(JSONB)


joes = Family(meta=[
    {
        "name": "Joe",
        "children": [
            {
                "name": "Jane"
            },
            {
                "name": "Kate"
            }
        ]
    },
    {
        "name": "Lisa",
        "children": [
            {
                "name": "Mary"
            },
            {
                "name": "David"
            }
        ]
    },
])

Есть ли способ запросить всех детей с определенной подстрокой в ​​их именах?

Если я захочу запросить 'a', я получу Mary, David, Kate, Jane.

Я думал, может быть, что-то вроде

Family.query.filter(
    Family.meta.contains([{"children": [{"name": func.contains("a")}]}])
)

1 Ответ

0 голосов
/ 13 февраля 2019

Хитрость заключается в том, чтобы развернуть массив или массивы с помощью jsonb_array_elements(), а затем отфильтровать:

meta_value = literal_column('meta.value', type_=JSONB)
children_value = literal_column('children.value', type_=JSONB)

Family.query.\
    with_entities(children_value['name'].astext).\
    select_from(
        Family,
        func.jsonb_array_elements(Family.meta).alias('meta'),
        func.jsonb_array_elements(
            meta_value['children']).alias('children')).\
    filter(children_value['name'].astext.contains('a'))

Обратите внимание на использование literal_column() дляссылка на значения возвращаемой функции набора jsonb_array_elements().

...