I am trying to write a function for a given user to return a count of all online users and offline users for each chatroom the given user is a part of.
The methods listed below achieve what I want but it writes multiple queries to postgres and I want to be able to do it in one query.
class Users(Base): id: Mapped[uuid:UUID] = mapped_column( UUID(as_uuid=True), unique=True, default=uuid.uuid4, autoincrement=True ) username: Mapped[str] = mapped_column(String, primary_key=True, unique=True) password: Mapped[str] = mapped_column(String, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, default=datetime.now ) sessions: Mapped[List["Sessions"]] = relationship( back_populates="user", lazy="selectin" ) messages: Mapped[List["Messages"]] = relationship( back_populates="user", lazy="selectin" ) created_chatrooms: Mapped[List["Chatrooms"]] = relationship( back_populates="created_by", lazy="selectin" ) chatrooms: Mapped[List["Chatrooms"]] = relationship( secondary=user_chatroom_table, back_populates="users" ) online: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) async def get_chatrooms_and_user_counts(self, db: AsyncSession): chatroom_ids = await self.get_user_chatrooms(db=db) chatrooms_info = [] for chatroom_id in chatroom_ids: online_count_stmt = ( select(func.count()) .select_from( user_chatroom_table.join( Users, user_chatroom_table.c.user_id == Users.id ) ) .where( user_chatroom_table.c.chatroom_id == chatroom_id, Users.online == True, ) ) offline_count_stmt = ( select(func.count()) .select_from( user_chatroom_table.join( Users, user_chatroom_table.c.user_id == Users.id ) ) .where( user_chatroom_table.c.chatroom_id == chatroom_id, Users.online == False, ) ) online_count_result = await db.execute(online_count_stmt) offline_count_result = await db.execute(offline_count_stmt) online_count = online_count_result.scalar() offline_count = offline_count_result.scalar() chatrooms_info.append( {"chatroom_id": str(chatroom_id),"online": online_count,"offline": offline_count, } ) return chatrooms_info async def get_user_chatrooms(self, db: AsyncSession) -> List["Chatrooms"]:""" Asynchronously get a list of chatrooms that the given user is a part of. :param user_id: UUID of the user to check. :param db: SQLAlchemy AsyncSession. :return: List of Chatrooms the user is a part of.""" # Create a query that selects chatrooms joined by the given user_id stmt = ( select(Chatrooms.id) .join( user_chatroom_table, Chatrooms.id == user_chatroom_table.c.chatroom_id ) .where(user_chatroom_table.c.user_id == self.id) ) result = await db.execute(stmt) chatrooms = result.scalars().all() return chatroomsclass Chatrooms(Base): id: Mapped[uuid:UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, unique=True, default=uuid.uuid4, ) name: Mapped[str] = mapped_column(unique=True, nullable=False) created_by: Mapped["Users"] = relationship( back_populates="created_chatrooms", lazy="selectin" ) user_id: Mapped[uuid:UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id") ) created_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, default=datetime.now ) category: Mapped[str] = mapped_column(nullable=False) messages: Mapped[List["Messages"]] = relationship( back_populates="chatroom", lazy="selectin" ) users: Mapped[List[Users]] = relationship( secondary=user_chatroom_table, back_populates="chatrooms" )