2017-07-04 65 views
0

我需要构造以下SQL查询:SQLAlchemy的 - 查询和过滤的嵌套jsonb字段

SELECT 
    distinct entity.id, 
    item_keys 
FROM entity 
    jsonb_each(entity.jsonb) item, -- extracts first level 
    jsonb_each(entity.value) as item_values, -- extracts keys from first level 
    jsonb_array_elements(item_values.value) item_keys -- 
WHERE 
item_keys->>'key' = 'somevalue'; 

我有一个嵌套的JSON存储在列中,所以我需要提取列出的值和滤波器对他们:

{"filters": 
    {"first_filter": [{"end": "100", "begin": "1"}], 
    {"second_filter": [{"end": "4095", "begin": "1"}] 
} 

目前我可以使用以下命令:

fields = [entity.c.id.label('id'), entity.c.jsonb.label('jsonb')] 

n1 = (Grouping(func.jsonb_each(entity.c.jsonb)).op('.')(literal_column('value')).label('level1')) 
n2 = (Grouping(func.jsonb_each(n1)).op('.')(literal_column('value')).label('level2')) 
filter_value = (Grouping(func.jsonb_array_elements(n2)).label('filter_value')) 

filter_sql = select([filter_value]).alias('filters') 

sql = select(fields, distinct=True).select_from(filter_value) 
sql.where(literal_column(filter.value).op('->>')('key') == 'value') 

将会产生以下曲ery:

SELECT 
    DISTINCT entity.id AS entity_id, 
    companies_company.slug AS slug 
    et.work_hours_time_ranges AS schedule_set_work_hours_time_ranges 
FROM 
entity, 
(SELECT 
    (jsonb_array_elements(
     (jsonb_each(
      (jsonb_each(entity.jsonb)) . value) 
     ) . value) 
    ) AS filter_value FROM entity) AS filters 
WHERE 
filter.filter_value ->> 'key' <= 'value'; 

并返回无效结果 - 双打实体。

+0

生成的查询似乎没有用给定的Python。 –

+0

您可以使用['FunctionElement.alias()'](http://docs.sqlalchemy.org/en/latest/core/functions.html#sqlalchemy.sql.functions.FunctionElement.alias)来简化一些查询建设。 –

回答

-2

与往常一样,只要我张贴的问题我自己:)

中找到答案。由于在FROM子句中多了一个子查询,我需要与主句的加入一样好:

fields = [entity.c.id.label('id'), entity.c.jsonb.label('jsonb')] 

n1 = (Grouping(func.jsonb_each(entity.c.jsonb)).op('.')(literal_column('value')).label('level1')) 
n2 = (Grouping(func.jsonb_each(n1)).op('.')(literal_column('value')).label('level2')) 
filter_value = (Grouping(func.jsonb_array_elements(n2)).label('filter_value')) 

filter_sql = select([entity.c.id, filter_value]).alias('filters') 

sql = select(fields, distinct=True).select_from(filter_value) 
sql.where(and_([ 
    (literal_column(filter.value).op('->>')('key') == 'value'), 
    (literal_column('filters.id') == entity.c.id), 
])) 

和一切开始按预期工作。

+0

使用SQLAlchemy 1.1.9会引发一个异常:ArgumentError:FROM表达式。 –

+0

@IljaEverilä我实际上删除了一半的查询来简化它。可能在过程中犯了一个错误。没关系。其实我自己也找出了这个问题。 :) – bosha