Connecting nested records can be tricky, especially when working with undefined
values.
This article covers the problem you might face working with undefined
unique nested records, why that’s the case, and how to get around it.
The challenge of working with undefined
nested values
Assuming you have the following schema:
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
content String?
isPublished Boolean @default(false)
authorId Int?
author User? @relation(fields: [authorId], references: [id])
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
… and you’re creating a post record and want to connect an author, you can connect the author
relation directly using the foreign key as follows:
const authorId = undefined;
const newPost = await prisma.post.create({
data: {
title: "New Post with undefined authorId",
authorId,
},
});
When the value is set undefined
, it is equivalent to not having the field. The payload for the query would be equal to the following:
data: {
title: "New Post with undefined authorId";
}
Another way you can connect nested records is using a relation query ↗ as follows:
const authorId = undefined;
const newPost = await prisma.post.create({
data: {
title: "New Post with undefined authorId",
author: {
connect: { id: authorId },
},
},
});
However, in the above query, since the authorId
value is undefined
, the query’s payload would resemble this:
data: {
title: "New Post with undefined authorId";
author: {
connect: {
}
}
}
The above payload is invalid since the query expects a value in the connect
property.
On attempting to run the query, it will fail with the following error (Expand to view the error)
PrismaClientValidationError:
Invalid `prisma.post.create()` invocation in
/project_path/index.ts:8:37
5 async function main() {
6 const authorId = undefined
7
→ 8 const newPost = await prisma.post.create({
data: {
title: 'New Post with undefined authorId',
author: {
~~~~~~
connect: {
id: authorId
}
}
},
include: {
author: true
}
})
Unknown arg `author` in data.author for type PostUncheckedCreateInput. Did you mean `authorId`? Available args:
type PostUncheckedCreateInput {
id?: Int
createdAt?: DateTime
updatedAt?: DateTime
title: String
content?: String | Null
isPublished?: Boolean
authorId?: Int | Null
}
at Yn.validate (/project_path/node_modules/@prisma/client/src/runtime/query.ts:249:19)
at Ur.createMessage (//project_path/node_modules/@prisma/client/src/runtime/core/protocol/graphql.ts:81:14)
at cb (/Users/ruheni/project_path/node_modules/@prisma/client/src/runtime/getPrismaClient.ts:1078:27)
at runInChildSpan (/project_path/node_modules/@prisma/engine-core/src/tracing/runInChildSpan.ts:20:41)
at t._executeRequest (/project_path/node_modules/@prisma/client/src/runtime/getPrismaClient.ts:1077:31)
at async t._request (/project_path/node_modules/@prisma/client/src/runtime/getPrismaClient.ts:1036:14) {
clientVersion: '4.10.1'
}
Workaround for unique undefined
relation query
One workaround is by checking the value of the unique property using the &&
logical operator — authorId
in this case:
const authorId = undefined;
const newPost = await prisma.post.create({
data: {
title: "New Post with undefined authorId",
author: authorId && { connect: { id: authorId } },
},
});
The payload from the query would be as follows, which is valid:
data: {
title: "New Post with undefined authorId";
author: {
}
}
Here’s another possible workaround, with some type-safety, for skipping unique fields:
const authorId = undefined;
const connectAuthorId =
typeof authorId !== "undefined"
? {
connect: {
id: authorId,
} satisfies Prisma.UserCreateNestedOneWithoutPostsInput["connect"],
}
: {};
const newPost = await prisma.post.create({
data: {
title: "3rd Post with undefined authorId",
author: connectAuthorId,
},
});