1

I have a postgres table represented in the sql alchemy like

from sqlalchemy import Column
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class ListingDatabaseDocument(Base):
    __tablename__ = 'listing'
    uuid = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=True)
    doc = Column(JSONB, nullable=False)

My doc jsonb field looks like

{"name": "SOME_NAME", "features": ["BALCONY", "GARAGE", "ELEVATOR"]}

Now I'd like to get all rows where the doc->'features' array contains "ELEVATOR","GARAGE" - in pure sql I do it like

SELECT * FROM listing
WHERE doc -> 'features' @> ANY(ARRAY['["ELEVATOR","GARAGE"]']::jsonb[])

How to achieve this in SqlAlchemy ? I tried something like

from sqlalchemy.dialects.postgresql import JSONB, ARRAY
from sqlalchemy.sql.expression import cast
from sqlalchemy import any_

return session.query(ListingDatabaseDocument).filter(
    ListingDatabaseDocument.doc['features'].op('@>')(any_(cast(['ELEVATOR','GARAGE'], ARRAY(JSONB))))
).all()

but it's not working. Thanks for help !

1 Answer 1

1

If you enable logging in SQLAlchemy you can see that the SQLAlchemy version of the query is casting differently than the SQL version. Specifically it's casting to JSONB[] twice, whereas in the SQL version the casts are JSONB (implicit - the string is already JSON) and JSONB.

SELECT listing.uuid AS listing_uuid, listing.doc AS listing_doc 
  FROM listing 
  WHERE (listing.doc -> %(doc_1)s) @> ANY (CAST(%(param_1)s::JSONB[] AS JSONB[]))

Rather than trying to fix this, I think the SQL version can be simplified to

SELECT uuid, doc 
  FROM listing 
  WHERE doc -> 'features' @> '["ELEVATOR", "GARAGE"]';

And the SQLAlchemy equivalent would be

s.query(ListingDatabaseDocument)
.filter(
    ListingDatabaseDocument.doc['features'].op('@>')(
        sa.cast(['ELEVATOR', 'GARAGE'], JSONB)
    )
)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.