SQLALCHEMY/FASTAPI/POSTGRESQL |只检索双重条目
SQLALCHEMY/FASTAPI/POSTGRESQL | Only retrieve double entries
我有一个名为 friends
的 table 数据库。 table 有两列,"user_id" and "friend_id"
。
这些是来自 Users
table.
的外键
我的朋友 table 现在:
user_id | friend_id
-------------------------------------+-------------------------------------
google-oauth2|11539665289********** | google-oauth2|11746442253**********
google-oauth2|11746442253********** | google-oauth2|11539665289**********
google-oauth2|11746442253********** | google-oauth2|11111111111**********
前两行是相同的ID,但翻转了。那些 Users
我想检索,因为他们添加了彼此。第三行只加了一个人,那个不应该被找回来
我的 SQLModels (models.py):
class Friends(SQLModel, table=True):
__tablename__ = "friends"
user_id: str = Field(sa_column=Column('user_id', VARCHAR(length=50), primary_key=True), foreign_key="users.id")
friend_id: str = Field(sa_column=Column('friend_id', VARCHAR(length=50), primary_key=True), foreign_key="users.id")
class UserBase(SQLModel):
id: str
username: Optional[str]
country_code: Optional[str]
phone: Optional[str]
picture: Optional[str]
class Config:
allow_population_by_field_name = True
class User(UserBase, table=True):
__tablename__ = 'users'
id: str = Field(primary_key=True)
username: Optional[str] = Field(sa_column=Column('username', VARCHAR(length=50), unique=True, default=None))
phone: Optional[str] = Field(sa_column=Column('phone', VARCHAR(length=20), unique=True, default=None))
picture: Optional[str] = Field(sa_column=Column('picture', VARCHAR(length=255), default=None))
我的 fastapi 端点:
@router.get("", status_code=status.HTTP_200_OK, response_model=models.FriendsList, name="Get Friends for ID",
tags=["friends"])
async def get_friends(
user_id: str = Query(default=None, description="The user_id that you want to retrieve friends for"),
session: Session = Depends(get_session)
):
stm = select(models.User, models.Friends).where(models.User.id == models.Friends.friend_id, models.Friends.user_id == user_id)
res = session.exec(stm).all()
if not res:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="There are no friendships associated with this id.")
users = []
for item in res:
users.append(item[0])
return models.FriendsList(users=users)
我的代码工作得很好,只有查询需要被替换。
stm = select(models.User, models.Friends).where(models.User.id == models.Friends.friend_id, models.Friends.user_id == user_id)
res = session.exec(stm).all()
此查询 returns 每个 User
给定 ID 为 user_id
,但不检查是否有相反的条目。
我想要得到的示例:
我向 ID 为 google-oauth2|11746442253**********
的端点发出 GET 请求。我会得到用户 google-oauth2|11539665289**********
。 (用户 google-oauth2|11111111111**********
不会被检索到,因为没有相反的条目)
希望你们理解我的问题。如有任何问题,请随时提出。
此致,
科林
正如我在评论中所说,没有一个简单的例子我无法真正尝试自己,但我确实有一个想法。您可能需要稍微修改一下子查询语法,但我认为理论上这可行:
stmt = select(Friends.user_id, Friends.friend_id).where(
tuple_(Friends.user_id, Friends.friend_id).in_(select(Friends.friend_id, Friends.user_id))
)
基本上它只是检查每个 (user_id, friend_id)
是否有匹配的 (friend_id, user_id)
。
你能添加另一个名为“已接受”的列,其值为 0 或 1 吗?
user_id | friend_id | accepted
-------------------------------------+-----------------------------------------------
google-oauth2|11539665289********** | google-oauth2|11746442253********** | 1
google-oauth2|11746442253********** | google-oauth2|11539665289********** | 1
google-oauth2|11746442253********** | google-oauth2|11111111111********** | 0
那么你有两个选择:
你可以在用户 table 上建立一个名为“朋友”的关系,并将惰性参数设置为“动态”(lazy='dynamic'
),然后查询:user.friends.filter_by(accepted=1).all()
或者您可以编写如下查询:
query = Friends.query.filter(Friends.user_id==user_id).filter(Friends.accepted == 1).all()
一般而言,关系数据库不是这些类型场景的最佳解决方案 - 如果您非常灵活并且不太深入,您可以检查像 MongoDB
这样的 NoSQL 解决方案
我有一个名为 friends
的 table 数据库。 table 有两列,"user_id" and "friend_id"
。
这些是来自 Users
table.
我的朋友 table 现在:
user_id | friend_id
-------------------------------------+-------------------------------------
google-oauth2|11539665289********** | google-oauth2|11746442253**********
google-oauth2|11746442253********** | google-oauth2|11539665289**********
google-oauth2|11746442253********** | google-oauth2|11111111111**********
前两行是相同的ID,但翻转了。那些 Users
我想检索,因为他们添加了彼此。第三行只加了一个人,那个不应该被找回来
我的 SQLModels (models.py):
class Friends(SQLModel, table=True):
__tablename__ = "friends"
user_id: str = Field(sa_column=Column('user_id', VARCHAR(length=50), primary_key=True), foreign_key="users.id")
friend_id: str = Field(sa_column=Column('friend_id', VARCHAR(length=50), primary_key=True), foreign_key="users.id")
class UserBase(SQLModel):
id: str
username: Optional[str]
country_code: Optional[str]
phone: Optional[str]
picture: Optional[str]
class Config:
allow_population_by_field_name = True
class User(UserBase, table=True):
__tablename__ = 'users'
id: str = Field(primary_key=True)
username: Optional[str] = Field(sa_column=Column('username', VARCHAR(length=50), unique=True, default=None))
phone: Optional[str] = Field(sa_column=Column('phone', VARCHAR(length=20), unique=True, default=None))
picture: Optional[str] = Field(sa_column=Column('picture', VARCHAR(length=255), default=None))
我的 fastapi 端点:
@router.get("", status_code=status.HTTP_200_OK, response_model=models.FriendsList, name="Get Friends for ID",
tags=["friends"])
async def get_friends(
user_id: str = Query(default=None, description="The user_id that you want to retrieve friends for"),
session: Session = Depends(get_session)
):
stm = select(models.User, models.Friends).where(models.User.id == models.Friends.friend_id, models.Friends.user_id == user_id)
res = session.exec(stm).all()
if not res:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="There are no friendships associated with this id.")
users = []
for item in res:
users.append(item[0])
return models.FriendsList(users=users)
我的代码工作得很好,只有查询需要被替换。
stm = select(models.User, models.Friends).where(models.User.id == models.Friends.friend_id, models.Friends.user_id == user_id)
res = session.exec(stm).all()
此查询 returns 每个 User
给定 ID 为 user_id
,但不检查是否有相反的条目。
我想要得到的示例:
我向 ID 为 google-oauth2|11746442253**********
的端点发出 GET 请求。我会得到用户 google-oauth2|11539665289**********
。 (用户 google-oauth2|11111111111**********
不会被检索到,因为没有相反的条目)
希望你们理解我的问题。如有任何问题,请随时提出。
此致, 科林
正如我在评论中所说,没有一个简单的例子我无法真正尝试自己,但我确实有一个想法。您可能需要稍微修改一下子查询语法,但我认为理论上这可行:
stmt = select(Friends.user_id, Friends.friend_id).where(
tuple_(Friends.user_id, Friends.friend_id).in_(select(Friends.friend_id, Friends.user_id))
)
基本上它只是检查每个 (user_id, friend_id)
是否有匹配的 (friend_id, user_id)
。
你能添加另一个名为“已接受”的列,其值为 0 或 1 吗?
user_id | friend_id | accepted
-------------------------------------+-----------------------------------------------
google-oauth2|11539665289********** | google-oauth2|11746442253********** | 1
google-oauth2|11746442253********** | google-oauth2|11539665289********** | 1
google-oauth2|11746442253********** | google-oauth2|11111111111********** | 0
那么你有两个选择:
你可以在用户 table 上建立一个名为“朋友”的关系,并将惰性参数设置为“动态”(
lazy='dynamic'
),然后查询:user.friends.filter_by(accepted=1).all()
或者您可以编写如下查询:
query = Friends.query.filter(Friends.user_id==user_id).filter(Friends.accepted == 1).all()
一般而言,关系数据库不是这些类型场景的最佳解决方案 - 如果您非常灵活并且不太深入,您可以检查像 MongoDB
这样的 NoSQL 解决方案