python - 在使用 SQLAlchemy 的组合查询中,如何计算自引用关系(符合特定条件)的数量?

标签 python sql postgresql sqlalchemy flask-sqlalchemy

我有这样的模型:

class User(db.Model):
    id = db.Column(UUID_TYPE, primary_key=True)

class Post(db.Model):
    id = db.Column(UUID_TYPE, primary_key=True)
    private = db.Column(db.Boolean)

class PostSubscription(db.Model):
    user_id = db.Column(UUID_TYPE, db.ForeignKey("users.id"))
    user = db.relationship(
        "User", 
        backref=db.backref("subscriptions", cascade="all, delete-orphan")
    )
    post_id = db.Column(UUID_TYPE, db.ForeignKey("posts.id"))
    post = db.relationship(
        "Post",
        foreign_keys=[post_id],
        lazy="joined",
        backref=db.backref("subscriptions", cascade="all, delete-orphan"),
    )
    liked = db.Column(db.Boolean)

我有一个查询可以获取用户有权访问的所有私有(private) PostSubscription,例如

query = (db.session.query(PostSubscription)
    .filter(User.id == user_id, Post.private)
    .join(PostSubscription.post)
)

想在同一查询中获取Post 赞数(以避免N+1 问题) .我的问题是这些点赞本身存储在 PostSubscription 中,这是我首先获取的主要内容。所以整个困惑变得有点 self 参照/循环。

我最初的尝试涉及向 Post 模型添加一个属性,但如上所述,该解决方案存在 N+1 问题,例如

@property
def likes(self):
    return db.session.query(PostSubscription).filter_by(
        post_id=self.id, 
        liked=True
    ).count()

经过一些研究,我意识到我可能需要将 func.count 与 case 结合使用,但我不知道在我的特定用途中如何做到这一点案件。我想做的是:

query = (
    db.session.query(
        PostSubscription,
        func.count(case([Post.subscriptions.liked, Post.id]))
    )
    .filter(User.id == user_id, Post.private)
    .join(PostSubscription.post)
)

但这显然行不通,因为我无法引用这样的关系。这两个表已经加入,我只是不知道如何只获取我已经拥有的 Post 的订阅(链接到我正在获取的 PostSubscription ).

有什么想法吗?

最佳答案

您可以尝试以下 SQLAlchemy 查询:

from sqlalchemy.orm import aliased, contains_eager

u = 1
PS1 = aliased(PostSubscription)
PS2 = aliased(PostSubscription)

query = db.session.query(PS1, func.count(PS2.liked))\
    .join(Post, PS1.post_id == Post.id)\
    .join(PS2, PS2.post_id == PS1.post_id)\
    .options(contains_eager(PS1.post))\
    .filter(PS1.user_id == u, Post.private)\
    .group_by(PS1.id)

应该给出以下 SQL:

SELECT post.id AS post_id, 
       post.private AS post_private, 
       postsubscription_1.id AS postsubscription_1_id, 
       postsubscription_1.user_id AS postsubscription_1_user_id, 
       postsubscription_1.post_id AS postsubscription_1_post_id, 
       postsubscription_1.liked AS postsubscription_1_liked, 
       Count(postsubscription_2.liked) AS count_1 
FROM   postsubscription AS postsubscription_1 
       JOIN post ON postsubscription_1.post_id = post.id 
       JOIN postsubscription AS postsubscription_2 ON postsubscription_2.post_id = postsubscription_1.post_id 
WHERE  postsubscription_1.user_id = 1 
       AND post.private = 1 
GROUP  BY postsubscription_1.id 

然后你可以像这样执行和打印:

result = query.all()

for postsubscription, likes in result:
    print(postsubscription, likes)

关于python - 在使用 SQLAlchemy 的组合查询中,如何计算自引用关系(符合特定条件)的数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57685154/

相关文章:

python - 在 Flask 中的请求的生命周期内保留对象

Python 在大量数字中寻找模式?

sql - SSIS包执行抛出错误DTS_E_CANNOTACQUIRECONNECTIONFROMCONNECTIONMANAGER

sql - 合并或更新

MySQL 事务/提交查询

java - jooq - 如何在 jooq 中将数组绑定(bind)为参数 - PostgreSQL

postgresql - 如何为 PostgreSQL 创建自定义窗口函数? (移动平均示例)

python - 从 Python 中的 ONNX 模型获取预测

javascript - 无法让 JavaScript 连接到 Postgresql

python - 节俭 python - TApplicationException : Invalid method name