如何在SQLAlchemy的ORM中使用Postgresql的jsonb_each函数

时间:2018-08-15 17:59:30

标签: postgresql sqlalchemy

我试图通过sqlalchemy在postgres中编写一个函数来计算嵌套json值的平均值。我要平均的值在统计信息表中,带有一个scores列,该列包含这样的json字典(过滤到相关结构):{1:{'score':0.0},2:{'score' :0.0} ...}。

用postgres编写,查询如下:

SELECT *, avg((v->>'score')::float) AS average_score
FROM lms.statistics, jsonb_each(statistics.scores) js(k, v)
WHERE jsonb_typeof(scores) != 'null'
GROUP BY statistics.id

我主要将其转换为以下sqlalchemy代码:

(
  session.query(Statistics)
  .add_columns(literal_column("avg((v->>'score')::float)").label('average_score'))
  .filter(literal("jsonb_typeof(statistics.scores != 'null'"))
  .group_by(Statistics.id)
).all()

但是,无论我做什么,sqlalchemy都不允许我包含此查询所依赖的jsonb_each。我什至尝试重组查询以使用显式联接,而sqlalchemy的.join将不接受literal_column,文本或任何带有外部联接或指定伪联接条件的欺骗手段。当必须要使用sqlalchemy标准以将纯文本查询插入FROM或JOIN语句时,我尽力尝试这样做。

1 个答案:

答案 0 :(得分:2)

使用返回标量或一组单列的函数,您只需使用func.something.alias('x')column('x')。不幸的是,SQLAlchemy不支持显式地对列进行别名,因此处理返回多列组合的函数有些棘手。如果是jsonb_each the default names are key and value,那么您可以使用以下内容:

v = column('value', type_=JSONB)
score = v['score'].astext.cast(Float)

session.query(Statistics,
              func.avg(score).label('average_score')).\
    select_from(Statistics,
                func.jsonb_each(Statistics.scores).alias()).\
    filter(func.jsonb_typeof(Statistics.scores) != 'null').\
    group_by(Statistics.id)