I'm pretty new to Prisma / Nexus and GraphQL in general.
I had a pretty hard time defining a Prisma explicit many-to-many relationship field resolver in Nexus but I finally found 2 different working solutions.
Could someone tell me which solution is the best and why ? Where can I find some documentation about the pros / cons / perf of both solutions ?
schema.prisma
file
model User {
id Int @id @default(autoincrement())
email String @unique
password String
groups UsersOnGroups[]
recipes Recipe[]
lists List[]
}
model Group {
id Int @id @default(autoincrement())
name String
users UsersOnGroups[]
recipes Recipe[]
lists List[]
}
model UsersOnGroups {
user User @relation(fields: [userId], references: [id])
userId Int
group Group @relation(fields: [groupId], references: [id])
groupId Int
@@id([userId, groupId])
}
Only posting User
because Group
works basically the same. Some fields got omitted for brevity.
user.ts
file -> 1st solution
export const User = objectType({
name: 'User',
definition(t) {
t.nonNull.int('id')
t.string('email')
t.nonNull.list.nonNull.field('groups', {
type: Group,
resolve: async (parent, _args, context) => {
const groups = await context.prisma.usersOnGroups.findMany({
where: {
userId: parent.id,
},
include: {
group: true,
},
})
return groups.map((groupRelation) => groupRelation.group)
},
})
},
})
user.ts
file -> 2nd solution
export const User = objectType({
name: 'User',
definition(t) {
t.nonNull.int('id')
t.string('email')
t.nonNull.list.nonNull.field('groups', {
type: Group,
resolve: (parent, _args, context) => {
return context.prisma.group.findMany({
where: {
users: {
every: {
userId: parent.id,
},
},
},
})
},
})
},
})
Tried both solution and both return the same and correct values but I don't have enough data to test out the performances.
EDIT : Considering the N+1 issue, I came out with this other solution that's probably better.
t.nonNull.list.nonNull.field('groups', {
type: Group,
resolve: async (parent, _args, context: Context) => {
const groups = await context.prisma.user
.findUnique({
where: {
id: parent.id,
},
})
.groups({
include: {
group: true,
},
})
return groups?.map((groupRelation) => groupRelation.group) ?? []
},
})
I don't know which one is better, but you can test it out yourself with prisma info logs
You can check the duration of each query, and the number of queries, and compare them.
However, your biggest performance issue will be with the n+1 problem for both solutions: n+1 issue
If you cannot solve it with prisma, you can solve it with a dataloader