Models:
class Team(Base):
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
players = relationship("Player", backref="team")
class Player(Base):
id = Column(Integer, primary_key=True)
name = Column(String(255), unique=True)
team_id = Column(Integer, ForeignKey("team.id"))
positions = relationship("Position", backref="player")
class Position(Base):
id = Column(Integer(), primary_key=True)
name = Column(String(255), unique=True)
player_id = Column(Integer, ForeignKey("player.id"))
goals = relationship("Goal", backref="position")
class Goal(Base):
id = Column(Integer(), primary_key=True)
distance = Column(Integer)
position_id = Column(Integer, ForeignKey("position.id"))
# Query to get all goals of all players of a team
query = (
select(Team)
.select_from(Player, Position, Goal)
.options(joinedload(Team.players))
.options(
joinedload(
Team.players,
Player.positions,
)
)
.options(
joinedload(
Team.players,
Player.positions,
Position.goals,
)
)
result = await db.execute(query)
response = result.scalar()
Sample json output from above query,
{
"id": 3,
"players": [
{
"id": 3,
"positions": []
},
{
"id": 5,
"positions": [
{
"id": 7,
"goals": [
{
"id": 13,
}
]
}
]
},
{
"id": 1,
"positions": [
{
"id": 1,
"goals": [
{
"id": 16,
},
{
"id": 15,
},
{
"id": 14,
}
]
},
{
"id": 2,
"goals": [
{
"id": 4,
}
]
}
]
}
]
}
From sample json, we can clearly see that multiple goals are returned for a player id=1.
Now, I need to limit the query to last goal of each player, instead of all goals of that player.
So I tried,
subquery = (
select(Goal)
.order_by(Goal.id.desc())
.limit(1)
.subquery()
.lateral()
)
query = (
select(Team)
.select_from(Player, Position, Goal)
.options(joinedload(Team.players))
.options(
joinedload(
Team.players,
Player.positions,
)
)
.outerjoin(subquery)
.options(
contains_eager(
Team.players,
Player.positions,
Position.goals,
alias=subquery,
)
)
result = await db.execute(query)
response = result.scalar()
Sample json output from above query
{
"id": 3,
"players": [
{
"id": 3,
"positions": []
},
{
"id": 5,
"positions": [
{
"id": 7,
"goals": [
{
"id": 16,
}
]
}
]
},
{
"id": 1,
"positions": [
{
"id": 1,
"goals": [
{
"id": 16,
}
]
},
{
"id": 2,
"goals": [
{
"id": 16,
}
]
}
]
}
]
}
This fetches the last goal of any player, but not the last goal of respective player.
Filters like Goal.position_id == Position.id
in outerjoin
or subquery
either does not work or result in error.
Edit:
It looks like I need populate_existing(), but it's not available in new select
method.
Edit 2:
To simplify these queries, I am also thinking to create last_goal_id
column in position
table and update the position
table to store id of last inserted goal
. Are foreign keys to each other in 2 tables normal? goal
would have position_id
and position
would have last_goal_id
.
Team
from the database? And what is the purpose of modified query? Do you really need intermediary objects such asPosition
? Do you need it in the result, especially given that the last goal is not per Position, right? – Suffix