如何在SQLAlchemy中仅从JSON文本的第一层级获取值?

huangapple go评论72阅读模式
英文:

How to get values only from the 1st level of JSON text in SQLAlchemy?

问题

filtered_query = session.query(Citys).filter(
    ~func.json_extract(Citys.metadatas, '$.apps').cast(String).contains('message')).all()
英文:

I have a table like this

class City(Base):
    __tablename__ = 'Citys'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    metadatas = Column(String)

with these values

id=1, name="London", metadatas='{"lat":51.5072, "lon":0.1276, "Mayor": "Sadiq Khan", "participating":true, "apps":{"Facebook": {"messenger": true}, "Instagram":{"message":false}}}',
id=2, name="Liverpool", metadatas='{"lat":53.4084, "lon":2.9916, "Mayor": "Joanne Anderson", "participating":false, "apps":{"Twitter": {"messenger": true}, "telegram":{"message":false}}}',
id=3, name="Manchester", metadatas='{"lat":53.4808, "lon":2.2426, "Mayor": "Donna Ludford", "participating":true, "apps":{"TikTok": {"messenger": true}, "Google Meet":{"message":false}}}')]

the column metadatas is in json text format.

I want to implement a functionality that when a user searches for the app name it should return the id, name and metadatas related to it that filter app name.

for example if my search query is Facebook then it should return something like this

1 London {"lat":51.5072, "lon":0.1276, "Mayor": "Sadiq Khan", "participating":true, "apps":{"Facebook": {"messenger": true}, "Instagram":{"message":false}}}

if the user searches for something like message it shouldn't return anything.

Here's what I have implemented

filtered_query = session.query(Citys).filter(
    func.json_extract(Citys.metadatas, '$.apps').cast(String).like('%' + 'Facebook' + '%')).all()

and this returns me

1 London {"lat":51.5072, "lon":0.1276, "Mayor": "Sadiq Khan", "participating":true, "apps":{"Facebook": {"messenger": true}, "Instagram":{"message":false}}}

but when I search for message it returns

1 London {"lat":51.5072, "lon":0.1276, "Mayor": "Sadiq Khan", "participating":true, "apps":{"Facebook": {"messenger": true}, "Instagram":{"message":false}}}
2 Liverpool {"lat":53.4084, "lon":2.9916, "Mayor": "Joanne Anderson", "participating":false, "apps":{"vonage": {"messenger": true}, "telegram":{"message":false}}}
3 Manchester {"lat":53.4808, "lon":2.2426, "Mayor": "Donna Ludford", "participating":true, "apps":{"TikTok": {"messenger": true}, "Meet":{"message":false}}}

which is not my desired result for the second search query it should return empty data

答案1

得分: 1

正如我提到的,你可以使用 [`json_contains_path`](https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-contains-path) 如下所示:

with Session(engine) as session:
search_key = "Facebook"

filtered_query = (
    session.query(City)
    .filter(
        func.json_contains_path(City.metadatas, "one", f'$.apps."{search_key}"')
    )
    .all()
)

for i in filtered_query:
    print(i.name)

输出结果

`London`

如果我将 `search_key` 更改为 `message`,如预期那样,我什么都得不到。
英文:

As I mentioned you can use json_contains_path like so

with Session(engine) as session:
    search_key = "Facebook"

    filtered_query = (
        session.query(City)
        .filter(
            func.json_contains_path(City.metadatas, "one", f'$.apps."{search_key}"')
        )
        .all()
    )

    for i in filtered_query:
        print(i.name)

Output

London

If I change search_key to message, as expected, I get nothing.

huangapple
  • 本文由 发表于 2023年3月9日 19:45:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684160.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定