How to query over an attribute that consists of a string of JSON in SQLAlchemy?

Question:

So, I table that looks like this.

City
id(Integer),
name(String),
metadata(String)

and it consists of data like this

1, "London", "{'lat':51.5072, 'lon':0.1276, 'Mayor': 'Sadiq Khan', 'participating':True}",
2, "Liverpool", "{'lat':53.4084, 'lon':2.9916, 'Mayor': 'Joanne Anderson', 'participating':"False},
3, "Manchester", "{'lat'53.4808, 'lon':2.2426, 'Mayor': 'Donna Ludford, 'participating':True}"

Now as you can see that the metadata field is of type string and consists of a JSON that is obviously a string.

Now, I want to filter the results based on the keys of metadata for example I want to return those values that have participating set to True in the metadata.

Something like this

1, "London", "{'lat':51.5072, 'lon':0.1276, 'Mayor': 'Sadiq Khan', 'participating':True}",
3, "Manchester", "{'lat'53.4808, 'lon':2.2426, 'Mayor': 'Donna Ludford, 'participating':True}"

I tried doing this
db.session.query(City).filter(cast(eval(metadata['participating]), String) == True)

I get this error
NotImplementedError: Operator 'getitem' is not supported on this expression

How do I achieve the desired result

Asked By: Gerry Volta

||

Answers:

you can use Json lib:

  • First:
import json

# Get all Data
city_list = db.session.query(City).all()

Make filter list

filtered_city_list = []
  • Second:
    for city in city_list:
        metadata_dict = json.loads(city.metadata)
        if 'participating' in metadata_dict and metadata_dict['participating'] == True:
            filtered_city_list.append(city)

you can implement all of them in function and use it

Answered By: Daniel Mombeyni

Step:1 ==> Define the model class for the City table.

Step:2 ==> Define the query to filter the cities based on the ‘participating’ value in the metadata column.

Step:3 ==>Get the list of cities that are participating.

import json
from sqlalchemy import func


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


participating_cities_query = db.session.query(City).filter(
    func.json_extract(City.metadata, '$.participating').cast(Boolean) == True
)


participating_cities = participating_cities_query.all()


for city in participating_cities:
    print(city.id, city.name, city.metadata)
Answered By: Iqbal Hussain
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.