如何使用Sqlalchemy根据计算的json值选择Postgresql记录?

时间:2018-07-11 10:46:18

标签: python postgresql sqlalchemy

我有一个包含2列的postgres表,我在查询中使用该表:

start_date_detail: date 
flex: jsonb

弹性字段示例:

{
    "communication": [
        {
            "remind_on": "mxmw@cxla.nl",
            "type": "email",
            "remind_date": -150
        },
        {
            "remind_on": "+31612345678",
            "type": "sms",
            "remind_date": -360
        }
    ]
}

我需要选择所有提醒日期都在上周的记录,因此(伪代码):

(now() - 1-week) < (start_date_detail + remind_date) < now()

如何通过sqlalchemy来实现这一点?

因为它是查询中的计算值,所以我不知道该怎么做。 在postgres中,我提出了这个建议,并且可行:

SELECT * FROM time_item 
WHERE 
    (start_date_detail + INTERVAL '1 second' * (flex->'communication'->0->>'remind_date')::numeric <= NOW())
    OR (start_date_detail + INTERVAL '1 second' * (flex->'communication'->1->>'remind_date')::numeric <= NOW())

如何将其放入sqlalchemy?

还有一件事: 在上面的查询中,我将每个通讯项添加到where子句中。如何使它更灵活?那就是我不需要为每个通讯项都放一个where子句。

1 个答案:

答案 0 :(得分:2)

您可以使用jsonb_array_elements()将数组扩展为一组jsonb元素,然后可以在谓词中使用。 SQLAlchemy通过使用alias支持将函数表达式作为可选函数。使用诸如

的模型
In [4]: class TimeItem(Base):
   ...:     __tablename__ = 'time_item'
   ...:     id = Column(Integer, primary_key=True)
   ...:     start_date_detail = Column(Date)
   ...:     flex = Column(JSONB)
   ...:     

查询看起来像

In [39]: session.query(TimeItem).\
    ...:     select_from(TimeItem,
    ...:                 func.jsonb_array_elements(TimeItem.flex['communication']).
    ...:                     alias('comm')).\
    ...:     filter((TimeItem.start_date_detail +
    ...:             timedelta(seconds=1) *
    ...:             column('comm', type_=JSONB)['remind_date'].
    ...:                 astext.
    ...:                 cast(Integer)).
    ...:                     between(func.now() - timedelta(weeks=1),
    ...:                             func.now())).\
    ...:     all()

然后,您可以调整谓词以适合您的需求–我尝试按照您的示例进行操作,因为与现在之前的一周相比,remind_date被解释为与start_date_detail的偏移秒数。当查询诸如TimeItem之类的实体时,SQLAlchemy会基于对象身份进行自身的重复数据删除,因此查询可以省略SQL端DISTINCT,或者将数组元素移动到EXISTS子查询表达式中,等等。