在sqlalchemy查询中使用jsonb_array_elements

时间:2019-01-22 07:00:24

标签: python sqlalchemy

我正在使用SQLAlchemy ORM,并试图找出如何产生PostgreSQL查询的方式,

SELECT
    payments.*
FROM
    payments,
    jsonb_array_elements(payments.data #> '{refunds}') refunds
WHERE
    (refunds ->> 'created_at')
        BETWEEN '2018-12-01T19:30:38Z' AND '2018-12-02T19:30:38Z';

尽管包含开始日期和结束日期。

我已经能够接近:

refundsInDB = db_session.query(Payment).\
    filter(Payment.data['refunds', 0, 'created_at'].astext >= startTime,
           Payment.data['refunds', 0, 'created_at'].astext < stopTime ).\
    all()

但是,仅当退款(是JSONB数据中的嵌套数组)是{'refunds':[]}列表中的第一个元素时,此方法才有效,而上面的SQL查询将起作用,而不管退款列表中的位置如何

经过大量搜索后,似乎旧的SQLAlchemy github issue中有一些临时食谱,其中之一是关于在查询中使用jsonb_array_elements的内容,但我还无法完全使其以我想要的方式工作。

如果有帮助,我的Payment.data JSONB就像付款对象from the Square Connect v1 API一样,我正尝试使用{的嵌套created_at列表中的refunds日期来搜索数据{1}}个对象。

1 个答案:

答案 0 :(得分:1)

使用Query.select_from()function expression alias来执行查询:

# Create a column object for referencing the `value` attribute produced by
# the set of jsonb_array_elements
val = db.column('value', type_=JSONB)

refundsInDB = db_session.query(Payment).\
    select_from(
        Payment,
        func.jsonb_array_elements(Payment.data['refunds']).alias()).\
    filter(val['created_at'].astext >= startTime,
           val['created_at'].astext < stopTime ).\
    all()

请注意,取消嵌套jsonb数组并基于其进行过滤可能会为每个Payment产生多行,但是SQLAlchemy在查询单个实体时只会返回不同的实体。