Issue
I'm trying to filter artwork objects based on multiple fields, one of which is the tag name. However, it failed.
My data structure:
model artworks {
id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
title String @db.VarChar(255)
artistid String @db.Uuid
description String?
dataadded DateTime? @default(now()) @db.Time(6)
isavailable Boolean? @default(true)
imageurl String @db.VarChar(500)
artworkimages artworkimages[]
users users @relation(fields: [artistid], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_artistid")
artworktags artworktags[]
comments comments[]
likes likes[]
products products[]
}
model artworktags {
artworkid String @db.Uuid
tagid String @db.Uuid
artworks artworks @relation(fields: [artworkid], references: [id], onDelete: NoAction, onUpdate: NoAction)
tags tags @relation(fields: [tagid], references: [id], onDelete: NoAction, onUpdate: NoAction)
@@id([artworkid, tagid])
}
model tags {
id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
name String @db.VarChar(20)
description String? @db.VarChar(500)
color String? @db.VarChar(20)
createddate DateTime? @default(now()) @db.Timestamp(6)
isactive Boolean? @default(true)
artworktags artworktags[]
producttags producttags[]
}
Here is the getArtworks()
method:
export async function getArtworks(
page: number,
pageSize: number,
availability: boolean | null = null,
searchTerm?: string
): Promise<ArtworkWithImagesTagsAndArtist[]> {
try {
const included = availability === null ? {} : { isavailable: availability };
const searchFilter = searchTerm
? {
OR: [
{ title: { contains: searchTerm } },
{ description: { contains: searchTerm } },
{ users: { name: { contains: searchTerm } } },
{ artworktags: { tags: { name: { contains: searchTerm } } } },
{ artworkimages: { name: { contains: searchTerm } } },
],
}
: {};
const combinedFilter: any | undefined = { ...included, ...searchFilter };
const artworks = await prisma.artworks.findMany({
skip: (page - 1) * pageSize,
take: pageSize,
include: {
artworkimages: true,
artworktags: {
include: {
tags: true
}
},
users: true
},
where: combinedFilter,
});
return artworks;
} catch (error) {
console.error('Failed to fetch artworks:', error);
throw new Error('Failed to fetch artworks.');
}
}
Here is the error message:
Failed to fetch artworks: PrismaClientValidationError:
Invalid `prisma.artworks.findMany()` invocation:
{
skip: 0,
take: 10,
include: {
artworkimages: true,
artworktags: {
include: {
tags: true
}
},
users: true
},
where: {
OR: [
{
title: {
contains: "test"
}
},
{
description: {
contains: "test"
}
},
{
users: {
name: {
contains: "test"
}
}
},
{
artworktags: {
tags: {
name: {
contains: "test"
}
}
}
},
{
artworkimages: {
name: {
contains: "test"
}
}
}
]
}
}
Unknown argument `tags`. Available options are marked with ?.
at ti (G:\Work\node_modules\@prisma\client\runtime\library.js:118:5888)
at si.handleRequestError (G:\Work\node_modules\@prisma\client\runtime\library.js:125:6473)
at si.handleAndLogRequestError (G:\Work\node_modules\@prisma\client\runtime\library.js:125:6151)
at si.request (G:\Work\node_modules\@prisma\client\runtime\library.js:125:5859)
at async l (G:\Work\node_modules\@prisma\client\runtime\library.js:130:10025)
at async getArtworks (webpack-internal:///(action-browser)/./src/lib/actions.ts:152:26)
at async G:\Work\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:39:406
at async t0 (g:\Work\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:38:5773)
at async rh (g:\Work\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:39:23636)
at async doRender (g:\Work\node_modules\next\dist\server\base-server.js:1391:30)
at async cacheEntry.responseCache.get.routeKind (g:\Work\node_modules\next\dist\server\base-server.js:1552:28)
at async DevServer.renderToResponseWithComponentsImpl (g:\Work\node_modules\next\dist\server\base-server.js:1460:28)
at async DevServer.renderPageComponent (g:\Work\node_modules\next\dist\server\base-server.js:1843:24)
at async DevServer.renderToResponseImpl (g:\Work\node_modules\next\dist\server\base-server.js:1881:32)
at async DevServer.pipeImpl (g:\Work\node_modules\next\dist\server\base-server.js:909:25)
at async NextNodeServer.handleCatchallRenderRequest (g:\Work\node_modules\next\dist\server\next-server.js:266:17)
at async DevServer.handleRequestImpl (G:\Work\node_modules\next\dist\server\base-server.js:805:17) {name: 'PrismaClientValidationError', clientVersion: '5.7.1', stack: 'PrismaClientValidationError:
Invalid `prisma…dules\next\dist\server\base-server.js:805:17)', message: '
Invalid `prisma.artworks.findMany()` invoca…`tags`. Available options are marked with ?.'}
Update:
Thanks to #37307554
I now updated my query to below and it works~!
{ artworkimages: { some:{ name: { contains: searchTerm, mode: 'insensitive' } } } }, { artworktags: { some: { tags: { name: { contains: searchTerm, mode: 'insensitive' } } } } },
Solution
In your getArtworks
function, the part of the query causing the error is:
{ artworktags: { tags: { name: { contains: searchTerm } } } }
You need to adjust the query to correctly filter based on the related tags
through artworktags
. The correct approach would be to use the some
filter on artworktags
to indicate that you're looking for artworks where at least one related artworktag
meets the condition.
Here's the adjusted query:
export async function getArtworks(
page: number,
pageSize: number,
availability: boolean | null = null,
searchTerm?: string
): Promise<ArtworkWithImagesTagsAndArtist[]> {
try {
const included = availability === null ? {} : { isavailable: availability };
const searchFilter = searchTerm
? {
OR: [
{ title: { contains: searchTerm, mode: 'insensitive' } },
{ description: { contains: searchTerm, mode: 'insensitive' } },
{ users: { name: { contains: searchTerm, mode: 'insensitive' } } },
{
artworktags: {
some: { tags: { name: { contains: searchTerm, mode: 'insensitive' } } }
}
},
{ artworkimages: { name: { contains: searchTerm, mode: 'insensitive' } } },
],
}
: {};
const combinedFilter: any | undefined = { ...included, ...searchFilter };
const artworks = await prisma.artworks.findMany({
skip: (page - 1) * pageSize,
take: pageSize,
include: {
artworkimages: true,
artworktags: {
include: {
tags: true
}
},
users: true
},
where: combinedFilter,
});
return artworks;
} catch (error) {
console.error('Failed to fetch artworks:', error);
throw new Error('Failed to fetch artworks.');
}
}
some
is used to specify that you're interested in artworks that have at least one tag matching the search term. This is the correct way to filter based on conditions in related records using Prisma. Also, I've added mode: 'insensitive'
to the contains
filters to make the search case-insensitive, which is desirable for text search, but you can remove it if case sensitivity is required.
Here is how your searchFilter
might look with all conditions, including the one for artworkimages
:
const searchFilter = searchTerm
? {
OR: [
{ title: { contains: searchTerm, mode: 'insensitive' } },
{ description: { contains: searchTerm, mode: 'insensitive' } },
{ users: { name: { contains: searchTerm, mode: 'insensitive' } } },
{
artworktags: {
some: { tags: { name: { contains: searchTerm, mode: 'insensitive' } } }
}
},
{
artworkimages: {
some: { name: { contains: searchTerm, mode: 'insensitive' } }
}
},
],
}
: {};
For artworkimages:
{
artworkimages: {
some: {
name: {
contains: searchTerm,
mode: 'insensitive'
}
}
}
}
For tags within artworktags:
{
artworktags: {
some: {
tags: {
name: {
contains: searchTerm,
mode: 'insensitive'
}
}
}
}
}
Answered By - 37307554
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.