Prisma: Most performant way to query for sub relations

2k views Asked by At

I want to query for posts and for each post I wan't just the like from the current user.

I have 2 solutions and both are working. But which one is better? Or are there better solutions?

  1. Frontend: React + ApolloClient
  2. Backend: Primsa2 + Graphql Nexus

Prisma Schema:

model Post {
  id            String         @id @default(cuid())
  likes         Like[]
}

model Like {
  id        String   @id @default(cuid())
  post      Post?    @relation(fields: [postId], references: [id])
  postId    String?
  user      User     @relation(fields: [userId], references: [id])
  userId    String
}

model User {
  id             String         @id @default(cuid())
  likes          Like[]
}

The queryField is the same for both solutions:

export const posts = queryField('posts', {
  type: 'Post',
  list: true,
  resolve: async (_parent, args: any, { prisma, request }, info) => {
    opArgs={
    //unimportant
    }

    return prisma.post.findMany(opArgs)
  },
})
  1. Solution: I make a request with the where condition for the like direct in the query with apollo client

Frontend: ApolloClient

const POSTS_USER = gql`
    query posts(
        $currentUserId: String
    ) {
        posts {
            id
            likes(where: { user: { id: { equals: $currentUserId } } }) { // where condition!
                id
            }
        }
        
    }
`;

const POSTS_NO_USER = gql`
    query posts(
        $currentUserId: String
    ) {
        posts {
            id
        }
        
    }
`;

const { data, loading } = useQuery(user? POSTS_USER: POSTS_NO_USER, {
        variables: {
            currentUserId: user ? user.id : "",
        },
});

Backend Nexus Object:

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.model.id()
    t.model.likes({
      filtering: {
        user: true,
      },
    })
  },
})
  1. Solution: I make for the objectType Post a field condition for the likes.

Frontend: ApolloClient

const POSTS = gql`
    query posts {
        posts {
            id
            likes { // NO where condition!
                id
            }
        }
        
    }
`;

const { data, loading } = useQuery(POSTS);

Backend with Nexus:

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.model.id()
    t.model.likes()
    t.list.field('likes', {
      type: 'Like',
      list: true,
      resolve: (parent, args, { prisma, request }) => {
        const user = getUser(request, false)
        if (!user) {
          return []
        } else {
          return prisma.like.findMany({
            where: {
              postId: parent.id,
              userId: user.id,
            },
          })
        }
      },
    })
  },
})
1

There are 1 answers

0
Ahmed Elywa On BEST ANSWER

The first way is better why?

when you make the first query prisma will do your query in 1 DB query. when you make the second query you will have DB queries as you have posts number

And the best way to use my PrismaSelect plugin Prisma Select takes the info: GraphQLResolveInfo object in general graphql arguments (parent, args, context, info) to select object accepted by prisma client. The approach allows a better performance since you will only be using one resolver to retrieve all your request. By doing so, it also eliminates the N + 1 issue.

But you also will need to drop using nexus-plugin-prisma and use my pal.js CLI to auto-generate your CRUD