Zandew
Zandew

Reputation: 98

SqlAlchemy query and filter by number of relationships

So currently I have two classes Foo and Bar where

class Foo(db.Model):
    ...
    bars = db.relationship('Bar', backref='foo', lazy='dynamic')
    ...

Here, a Foo can have many Bar's. How can I query Foo such that I can filter by the number of Bar's? Something like Foo.query.filter(Foo.bars.count() == x).first()

Would there be another way to do this other than keeping a count variable?

Upvotes: 1

Views: 664

Answers (1)

snakecharmerb
snakecharmerb

Reputation: 55600

This SQL query would be one way of doing it (assuming x = 2):

SELECT parent.id, COUNT(child.tid) AS num_bars 
  FROM parent 
  JOIN child ON parent.id = child.tid 
  GROUP BY parent.id 
  HAVING COUNT(child.tid) = 2;

This would translate to (sqlalchemy):

import sqlalchemy as sa

x = 2
q = (session.query(Foo, sa.func.count(Bar.foo_id).label('num_bars'))
            .join(Bar)
            .group_by(Foo.id)
            .having(sa.literal_column('num_bars') == x)
            .from_self(Foo))

the flask-sqlalchemy equivalent would probably be

q = (db.session.query(Foo, sa.func.count(Bar.foo_id).label('num_bars'))
              .join(Bar)
              .group_by(Foo.id)
              .having(sa.literal_column('num_bars') >= x)
              .from_self(Foo))

Another way to do it would be to use a subquery:

SELECT parent.id 
FROM parent 
  WHERE (SELECT COUNT(1)
         FROM child 
           WHERE child.tid = parent.id
  ) = 2

which would look like this using SQLAlchemy:

subq = (session.query(sa.func.count(Bar.foo_id))
               .filter(Bar.foo_id == Foo.id)
               .scalar_subquery())
q = session.query(Foo).filter(subq == 2)

Upvotes: 1

Related Questions