tRPC query 'train'. what's the correct method to grab data from multiple sources?

I'm going to make an example as I'm either struggling to understand or am building my database wrong. A user has a profile page, to load this profile page we use the URL value. So I query tRPC when the username is entered into the URL /profile/Debaucus I now get back the details for Debaucus, it's a real page. Next, I want to query all the users posts, stored in a separate table, called posts. If I make a new tRPC query, I get the 'too many re-renders' as I am doing multiple chains, as I am using the ID recovered from the first query in the second Load page > use slug for tRPC query to get data > use that data to tRPC query more data? Is this incorrect methodology?
9 Replies
Ramsay
Ramsay2y ago
This is known as a waterfall and should be avoided since it’s slow. You should have all the info you need from the url tho. What info are using from the first query that you don’t have from the url? If you need the posts for Debaucus, then why not just select all posts where user is Debaucus?
delavalom
delavalom2y ago
I don't think you need to query from multiple sources when your page load. If you have your router file system like this:
├── src/
│ └── pages
│ └── profile
│ └──[username]
├── src/
│ └── pages
│ └── profile
│ └──[username]
You could do this:
// Inside your component
const { query, isReady } = useRouter()
// Fetch the router data
const { data: posts, isLoading } = trpc.user.getUserPosts.useQuery(
{ username: query.username,
// use the username route to query your db
{
enabled: router.isReady,
// wait until the useRouter() hook finished fetching the router data
}
)
// Inside your component
const { query, isReady } = useRouter()
// Fetch the router data
const { data: posts, isLoading } = trpc.user.getUserPosts.useQuery(
{ username: query.username,
// use the username route to query your db
{
enabled: router.isReady,
// wait until the useRouter() hook finished fetching the router data
}
)
I'm assuming this is the architecture of your tRPC server and that you're using ReactQuery
cyremur
cyremur2y ago
Yeah just make 1 trpc query that grabs everything you need in one trip to backend land.
Debaucus
Debaucus2y ago
Posted the question and went to bed, my bad! I have this in my tRPC public router
getUniqueUser: publicProcedure
.input(z.string())
.query(async ({ ctx, input }) => {
const uniqueServer = await ctx.prisma?.user.findFirst({
where: {
name: input,
},
});

if (!uniqueServer) {
throw new TRPCError({
code: "NOT_FOUND",
message: `No post with id '${input}'`,
});
}

return uniqueServer;
}),
getUniqueUser: publicProcedure
.input(z.string())
.query(async ({ ctx, input }) => {
const uniqueServer = await ctx.prisma?.user.findFirst({
where: {
name: input,
},
});

if (!uniqueServer) {
throw new TRPCError({
code: "NOT_FOUND",
message: `No post with id '${input}'`,
});
}

return uniqueServer;
}),
How do I return multiple pieces of data? I can add this in between them, waterfalling as described above, but I'm confused on how to return them all, or combine them?
});

const getPosts = await ctx.prisma.posts.findMany({
where: {
postAuthor: uniqueServer.id
}
})

if (!uniqueServer) {
});

const getPosts = await ctx.prisma.posts.findMany({
where: {
postAuthor: uniqueServer.id
}
})

if (!uniqueServer) {
delavalom
delavalom2y ago
The Prisma client it's very flexible, you can query relations between tables, this allows you to avoid extra calls to the db in this procedure. In this case it will be like this:
getUniqueUser: publicProcedure
.input(z.string())
.query(async ({ ctx, input }) => {
const uniqueServer = await ctx.prisma?.user.findUnique({
where: {
name: input,
},
include: {
posts: true, // here you saying to prisma to return the posts related to this user
},
});

if (!uniqueServer) {
throw new TRPCError({
code: "NOT_FOUND",
message: `No post with id '${input}'`,
});
}

return uniqueServer;
}),
getUniqueUser: publicProcedure
.input(z.string())
.query(async ({ ctx, input }) => {
const uniqueServer = await ctx.prisma?.user.findUnique({
where: {
name: input,
},
include: {
posts: true, // here you saying to prisma to return the posts related to this user
},
});

if (!uniqueServer) {
throw new TRPCError({
code: "NOT_FOUND",
message: `No post with id '${input}'`,
});
}

return uniqueServer;
}),
To know more about you can refer to the prisma [docs] (https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries).
Debaucus
Debaucus2y ago
That's different to my post above, I am querying .posts, a separate table, after .user which I use the slug to get in id from. Judging by the responses, this looks like my database needs a refactor, so I query .user and in user I store the posts.
cyremur
cyremur2y ago
The include uses foreign reference to fetch posts that belong to a user in sql.
Debaucus
Debaucus2y ago
Hey, sorry for the delayed response, is there a help doc on this?
cyremur
cyremur2y ago
https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries Note that this only works if your db tables are designed correctly with foreign keys
Prisma
Relation queries (Concepts)
Prisma Client provides convenient queries for working with relations, such as a fluent API, nested writes (transactions), nested reads and relation filters.
Want results from more Discord servers?
Add your server