Pergunta

Estou tentando gerar uma consulta e tendo dificuldade em encontrar a maneira mais eficiente de fazer isso no sqlalchemy (observe que estou usando flask-sqlalchemy)

O objetivo é descobrir que todos os usuários se reuniram com um usuário específico.

Digamos que Frank tenha 10 reuniões marcadas. Quero gerar uma lista de todas as pessoas com quem Frank tem reuniões.

Aqui estão meus modelos:

class UserMeeting(db.Model):
    """ Associative table, links meetings to users in a many to many fashion"""
    __tablename__ = 'userMeeting'
    id = db.Column(db.Integer, primary_key = True)
    meeting_id = db.Column(db.Integer, db.ForeignKey('meeting.id'), primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)

class Meeting(db.Model):
    __tablename__ = "meeting"
    id = db.Column(db.Integer, primary_key = True)
    title = db.Column(db.String(128))
    #... other columns
    #associative reference
    attendees = db.relationship('UserMeeting', backref='meeting')

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key = True)
    email = db.Column(db.String(128), index=True, unique=True)
    password = db.Column(db.String(128))
    #associative reference
    attendingMeetings = db.relationship("UserMeeting", backref="user", cascade="all, delete-orphan") 

Aqui está o que eu tentei:

#Assume frank's a user with id == 1
frank = User.query.get(1)
franks_meetings = Meeting.query.join(Meeting.attendees).filter(UserMeeting.user == frank).all()
#not efficient way of getting users in meetings with frank
users = []
for meeting in franks_meetings:
    for userMeeting in meeting.attendees:
        if userMeeting.user != frank:
            users.append(userMeeting.user)

#is there a way to just generate one query and get this data?

Parece que estou sentindo falta de como poderia usar junções para obter esses dados.Qualquer ajuda seria apreciada!

Foi útil?

Solução

Você precisa ingressar na tabela UserMeeting com ela mesma, usando Meeting_id como chave de junção.Talvez seja necessário criar um alias para a tabela para referenciá-la duas vezes.Não sei se consigo digitar a sintaxe sqlalchemy de cara, mas o sql se parece com:

select distinct(b.user_id) as other_user_id
from usermeeting a
inner join usermeeting b
on a.meeting_id=b.meeting_id
where a.user_id=1 and b.user_id != 1;

E 1 é Frank.

Ah, e obter os detalhes do usuário também.Provavelmente você poderia acabar com User objetos diretamente de fazer isso no sqlalchemy:

select distinct(u.id), u.email
from usermeeting a
inner join usermeeting b
on a.meeting_id=b.meeting_id
inner join users u
on b.user_id=u.id
where a.user_id=1 and b.user_id != 1;

Outras dicas

Aqui está a versão sqlalchemy da consulta para referência:

#get all users in meetings with Frank, (frank.id == 1)
um = aliased(UserMeeting)
frank = User.query.get(1)

q = session.query(User).join(User.attendingMeetings).\
    filter(UserMeeting.meeting_id == um.meeting_id).\
    filter(UserMeeting.user_id != frank.id, um.user_id == frank.id)

users_meeting_with_frank = q.all()
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top