-
Notifications
You must be signed in to change notification settings - Fork 228
Description
I have a naive question but I don't know the words to search for. I'm sure this has been asked one million times but I'm clueless.
I have some blog posts with likes on them and I would like to query a list of blog posts with a flag on each post to tell wether the given user liked the post or not.
My current solution:
- I added a field in my schema (under
schema.Blog.has_user_liked
) - I added
lazy="dynamic"
onmodels.Blog.likes
so I can filter likes for a particular user
I wonder if this is the right approach as it makes "a lot" of disjoint SQL requests (at least one to get the blog posts and one per blog post). It sounds like a lot to me, but as I understand there is a compromise here because this will allow to only retrieve some blog posts (not ALL) and still have decent performances since it will not join very large tables. Note that I never plan on using this has_user_liked
field anywhere else but in a web view with pagination.
Is this the "right" solution? Is there a better way to achieve this? I would really appreciate any comment/critic about this.
Details about this solution
My model looks like this:
class User(database.Base):
user_id = IDColumn()
class Blog(database.Base):
blog_id = IDColumn()
likes = relationship("Like", back_populates="blog", lazy="dynamic")
class Like(database.Base):
blog_id = IDColumn(ForeignKey(Blog.blog_id))
user_id = IDColumn(ForeignKey(User.user_id))
blog = relationship("Blog", back_populates="likes")
My schema looks like this:
class User(SQLAlchemyObjectType):
class Meta:
model = models.User
interfaces = (Node,)
class Blog(SQLAlchemyObjectType):
class Meta:
model = models.Blog
interfaces = (Node,)
has_user_liked = graphene.Field(
graphene.Boolean, user_id=graphene.String(required=True)
)
def resolve_has_user_liked(self: models.Blog, info, user_id):
return self.likes.filter(user_id == user_id).count()
class Like(SQLAlchemyObjectType):
class Meta:
model = models.Like
interfaces = (Node,)
class Query(graphene.ObjectType):
node = Node.Field()
blogs = SQLAlchemyConnectionField(Blog)
If I make a request like this one:
query Test($userId: String!) {
blogs{
edges {
node {
id
hasUserLiked(userId: $userId)
}
}
}
}
I get the expected result (in my test DB I have 3 posts, one of which has one like from the given user):
{
"data": {
"blogs": {
"edges": [
{
"node": {
"id": "Blog:fdb231cd-2a19-4d1f-9443-5717f44275af",
"hasUserLiked": false
}
},
{
"node": {
"id": "Blog:375afe8e-a52a-4098-98b7-f04a4b504097",
"hasUserLiked": false
}
},
{
"node": {
"id": "Blog:01580847-bb33-40ef-93e4-8025a1e31145",
"hasUserLiked": true
}
}
]
}
}
}
The "problem" or rather my question concerns the generated SQL queries, from what I can see in SQLAlchemy's log, here is what the requests are:
SELECT count(*) AS count_1
FROM (SELECT "user".blog.blog_id AS user_blog_blog_id, "user".blog.author AS user_blog_author, "user".blog.date AS user_blog_date, "user".blog.title AS user_blog_title, "user".blog.content AS user_blog_content, "user".blog.image AS user_blog_image, "user".blog.avatar AS user_blog_avatar
FROM "user".blog) AS anon_1
SELECT count(*) AS count_1
FROM (SELECT "user".blog.blog_id AS user_blog_blog_id, "user".blog.author AS user_blog_author, "user".blog.date AS user_blog_date, "user".blog.title AS user_blog_title, "user".blog.content AS user_blog_content, "user".blog.image AS user_blog_image, "user".blog.avatar AS user_blog_avatar
FROM "user".blog) AS anon_1
SELECT "user".blog.blog_id AS user_blog_blog_id, "user".blog.author AS user_blog_author, "user".blog.date AS user_blog_date, "user".blog.title AS user_blog_title, "user".blog.content AS user_blog_content, "user".blog.image AS user_blog_image, "user".blog.avatar AS user_blog_avatar
FROM "user".blog
LIMIT %(param_1)s
SELECT "user".blog.blog_id AS user_blog_blog_id, "user".blog.author AS user_blog_author, "user".blog.date AS user_blog_date, "user".blog.title AS user_blog_title, "user".blog.content AS user_blog_content, "user".blog.image AS user_blog_image, "user".blog.avatar AS user_blog_avatar
FROM "user".blog
LIMIT %(param_1)s
-- User's likes
SELECT count(*) AS count_1
FROM (SELECT "user"."like".like_id AS user_like_like_id, "user"."like".blog_id AS user_like_blog_id, "user"."like".user_id AS user_like_user_id
FROM "user"."like"
WHERE %(param_1)s = "user"."like".blog_id) AS anon_1
SELECT count(*) AS count_1
FROM (SELECT "user"."like".like_id AS user_like_like_id, "user"."like".blog_id AS user_like_blog_id, "user"."like".user_id AS user_like_user_id
FROM "user"."like"
WHERE %(param_1)s = "user"."like".blog_id) AS anon_1
-- {'param_1': UUID('fdb231cd-2a19-4d1f-9443-5717f44275af')}
SELECT count(*) AS count_1
FROM (SELECT "user"."like".like_id AS user_like_like_id, "user"."like".blog_id AS user_like_blog_id, "user"."like".user_id AS user_like_user_id
FROM "user"."like"
WHERE %(param_1)s = "user"."like".blog_id) AS anon_1
SELECT count(*) AS count_1
FROM (SELECT "user"."like".like_id AS user_like_like_id, "user"."like".blog_id AS user_like_blog_id, "user"."like".user_id AS user_like_user_id
FROM "user"."like"
WHERE %(param_1)s = "user"."like".blog_id) AS anon_1
-- {'param_1': UUID('375afe8e-a52a-4098-98b7-f04a4b504097')}
SELECT count(*) AS count_1
FROM (SELECT "user"."like".like_id AS user_like_like_id, "user"."like".blog_id AS user_like_blog_id, "user"."like".user_id AS user_like_user_id
FROM "user"."like"
WHERE %(param_1)s = "user"."like".blog_id) AS anon_1
SELECT count(*) AS count_1
FROM (SELECT "user"."like".like_id AS user_like_like_id, "user"."like".blog_id AS user_like_blog_id, "user"."like".user_id AS user_like_user_id
FROM "user"."like"
WHERE %(param_1)s = "user"."like".blog_id) AS anon_1
-- {'param_1': UUID('01580847-bb33-40ef-93e4-8025a1e31145')}