简体   繁体   English

如何使用SqlAlchemy查询Postgres中的JSON数组?

[英]How to query JSON Array in Postgres with SqlAlchemy?

I have a SqlAlchemy model defined 我定义了一个SqlAlchemy模型

from sqlalchemy.dialects.postgresql import JSONB

class User(db.Model):
    __tablename__ = "user"
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(255), nullable=False)
    city = db.Column(db.String(255))
    contact_list = db.Column(JSONB)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

def add_user():
    user = User(nickname="Mike")
    user.contact_list = [{"name": "Sam", "phone": ["123456", "654321"]}, 
                         {"name": "John", "phone": ["159753"]},
                         {"name": "Joe", "phone": ["147889", "98741"]}]
    db.session.add(user)
    db.session.commit()

if __name__ == "__main__":
    add_user()

How can I retrieve the name from my contact_list using phone ? 如何使用手机从我的contact_list中检索姓名 For example, I have the 147889 , how can I retrieve Joe ? 例如,我有147889 ,我怎样才能找回

I have tried this 我试过这个

User.query.filter(User.contact_list.contains({"phone": ["147889"]})).all()

But, it returns me an empty list, [] 但是,它返回一个空列表, []

How can I do this? 我怎样才能做到这一点?

You just forgot that your JSON path should include the outermost array as well: 您忘记了您的JSON路径也应该包含最外层的数组:

User.query.filter(User.contact_list.contains([{"phone": ["147889"]}])).all()

will return the user you are looking for. 将返回您要查找的用户。 The original query would match, if your JSON contained an object with key "phone" etc. Note that this returns the User object in question, not the specific object/name from the JSON structure. 如果您的JSON包含具有键“phone”等的对象,则原始查询将匹配。请注意,这将返回有问题的User对象,而不是JSON结构中的特定对象/名称。 If you want that, as seems to be the end goal, you could expand the array elements of each user, filter based on the resulting records, and select the name: 如果你想要这样,似乎是最终目标,你可以扩展每个用户的数组元素,根据结果记录进行过滤,并选择名称:

val = db.column('value', type_=JSONB)
db.session.query(val['name'].astext).\
    select_from(User,
                db.func.jsonb_array_elements(User.contact_list).alias()).\
    filter(val.contains({"phone": ["147889"]})).\
    all()

On the other hand the above query is not as index friendly as the first one can be, because it has to expand all the arrays before filtering, so it might be beneficial to first find the users that contain the phone in their contact list in a subquery or CTE, and then expand and filter. 另一方面,上面的查询并不像第一个查询那样友好,因为它必须在过滤之前扩展所有数组,因此首先在其联系人列表中查找包含电话的用户可能是有益的。子查询或CTE,然后展开和过滤。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM