I have a DB with posts and tags. I want to find posts that only contain 1 tag with a specific tagId and no other tags at all. The code below works, but it requires the server to filter the results manually which will make pagination difficult. Does anyone have a direct query that can do this?
I tried a groupBy on postId in PostTag, but the issue is when I search for the tagId in a where clause then all entries on the PostTag only have 1 entry which makes counting impossible.
I am using Prisma as a wrapper for a PostgresQL DB.
const query = await prisma.post.findMany({
where: {
tags: {
some: {
tagId: Number(tagId),
}
},
},
select: {
id: true,
tags: {
select: {
tagId: true,
}
}
},
})
const tagIds = query
.filter(item => item.tags.length === 1)
.map(item => ({ id: item.id }));
Models
model Post {
id Int @id @default(autoincrement())
tags PostTag[]
}
//Pivot Table
model PostTag {
id Int @id @default(autoincrement())
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
postId Int
tag Tag @relation(fields: [tagId], references: [id])
tag Id Int
}
model Factiii {
id Int @id @default(autoincrement())
tags PostTag[]
}
2
Answers
I think the keyword here is
having
which unfortunately Prisma doesn’t yet support in where clauses.They support
having
in thegroupBy
function, but that doesn’t allow you to check based on the count.You can try this, which feels like a workaround but could work in your case:
The idea here is that since a post can contain a tag only once, if you provide only 1 value for comparison (
Number(tagId)
in this case) it can only match posts with one tag, which is the tag you care about. if my logic is wrong, please kindly let me knowAlternatively, you can consider doing a raw query with Prisma where you supply your own SQL code directly.
If you’re doing that, BE CAREFUL! Read more about raw queries with Prisma to be safe against SQL injections.
Here is the SQL code you can use for this purpose:
you could try this from Rayan answer on this question
where: { tags: { some: { tag: { id: 1 } } } }
})