Reputation: 1042
I'm trying to implement some kind of a basic social network project. It has Posts
, Comments
and Likes
like any other.
I have a /posts
route on the client application. It lists the Posts
by paginating and shows their title
, image
, authorName
, commentCount
and likesCount
.
The graphql
query is like this;
query {
posts(first: 10, after: "123456") {
totalCount
edges {
node {
id
title
imageUrl
author {
id
username
}
comments {
totalCount
}
likes {
totalCount
}
}
}
}
}
I'm using apollo-server
, TypeORM
, PostgreSQL
and dataloader
. I use dataloader
to get author
of each post. I simply batch the requested authorIds
with dataloader
, get authors
from PostgreSQL
with a where user.id in authorIds
query, map the query result to the each authorId
. You know, the most basic type of usage of dataloader
.
But when I try to query the comments
or likes
connection under each post
, I got stuck. I could use the same technique and use postId
for them if there was no pagination. But now I have to include filter parameters for the pagination. And there maybe other filter parameters for some where
condition as well.
I've found the cacheKeyFn
option of dataloader. I simply create a string key for the passed filter object to the dataloader, and it doesn't duplicate them. It just passes the unique ones to the batchFn
. But I can't create a sql query with TypeORM
to get the results for each first
, after
, orderBy
arguments separately and map the results back to the function which called the dataloader.
I've searched the spectrum.chat
source code and I think they don't allow users to query nested connections. Also tried Github GraphQL Explorer and it lets you query nested connections.
Is there any recommended way to achieve this? I understood how to pass an object
to dataloader
and batch them using cacheKeyFn
, but I can't figure out how to get the results from PostgreSQL
in one query and map the results to return from the loader.
Thanks!
Upvotes: 5
Views: 2281
Reputation: 5240
So, if you restrict things a bit, this is doable. The restriction is to only allowed batched connections on the first page of results, e.g. so all the connections you're fetching in parallel are being done with the parameters. This is a reasonable constraint because it lets you do things like get the first 10 feed items and the first 3 comments for each of them, which represents a fairly typical use case. Trying to support independent pagination within a single query is unlikely to fulfil any real world use cases for a UI, so it's likely an over-optimisation. With this in mind, you can support the "for each parent get the first N children" use case with PostgreSQL using window.
It's a bit fiddly, but there are answers floating around which will get you in the right direction: Grouped LIMIT in PostgreSQL: show the first N rows for each group?
So use dateloader how you are with cacheKeyFn
, and let your loader function recognise whether you can perform the optimisation (e.g. after is null
and all other arguments are the same). If you can optimise, use a windowing query, otherwise do unoptimised queries in parallel as you would normally.
Upvotes: 1