If I understand your question correctly, the request body may optionally contain an id or be undefined. If the id is present in the request, you want to update the corresponding record. If it isn't, you want to create a new record.
upsert functionality requires a unique identifier that can be used by the database to check whether there is a matching record. The database will then decide what to do. However with an undefined value, prisma cannot work.
You could use a key that will not exist in the database in case the value of id is undefined to make upsert insert the record in this case.
await prisma.profile.upsert({
where: { id: id || '' },
// ...
});
Or you could differentiate the cases and treat them appropriately:
if (id) {
await prisma.profile.update({
where: { id },
data: {
username,
about,
// ...
},
});
} else {
await prisma.profile.create({
data: {
username,
about,
// ...
},
});
}
You might want to think about the case that there is an id given in the body, but it does exist in the database. Do you want the update to fail and reply with an error? Or do you want the database to silently insert? Then use upsert instead of update above.
how do I do this upsert query in prisma?
Use `INSERT ... ON CONFLICT DO NOTHING` instead of unexpected SELECT + INSERT on calling `upsert` with empty `update`
how to upsert many fields in prisma ORM
Provide `upsertMany()`/`upsertFirst()` operation in the client API
You can't do it right now in Prisma. There is createMany, updateMany and deleteMany, but no upsertMany. (Docs)
The most efficient way if you need to handle lots of data would probably be something like that:
prisma.$transaction([
prisma.posts.deleteMany({ where: { userId: 1 } }),
prisma.posts.createMany({
{ id: 1, title: 'first', userId: 1 },
{ id: 2, title: 'second', userId: 1 },
{ id: 3, title: 'third', userId: 1 },
}),
]);
So you delete existing records and then recreate them again inside of a transaction.
Depending on the database (and schema) you use, Prisma supports an optional boolean within a createMany call: skipDuplicates, see https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#createmany
Do not insert records with unique fields or ID fields that already exist. Only supported by databases that support ON CONFLICT DO NOTHING.
I have a question about nested upserts and if they're even possible.
I have a Prisma create that's working as expected;
An orders (table) can create an array of artwork (table), and the artwork can create an array of shirts (table).
The issue is when I want to update the shirts table through the order, similar to the create, with an upsert.
This block works as expected.
const CREATE = await prisma.orders.create({
data: {
artwork: {
create: artwork.map(art => {
return {
notes: art.notes,
shirts: {
create: art.shirts.map(shirt => ({
name: shirt.name,
url: shirt.url,
})),
},
};
})
}
},
});This block works to upsert the artwork, but fails when trying to upsert the shirts.
const UPDATE = await prisma.orders.create({
data: {
artwork: {
upsert: artwork.map(art => {
const updatedArtworkWithShirts = {
notes: art.notes,
shirts: {
upsert: art.shirts.map(shirt => {
const updatedShirt = {
name: shirt.name,
url: shirt.url,
};
return {
where: { id: shirt.id },
update: updatedShirt,
create: updatedShirt,
};
}),
},
};
return {
where: { id: art.id },
update: updatedArtworkWithShirts,
create: updatedArtworkWithShirts,
};
}),
},
}
});The error I'm receiving is:
Unknown arg `upsert` in data.artwork.upsert.0.create.shirts.upsert for type shirtsCreateNestedManyWithoutArtworkInput. Did you mean `select`?
Any thoughts? Am I approaching this incorrectly?
If you are still down here without an answer, I used a combination from @Antoine's answer and another SO answer:
model Likes {
id String @id @unique @default(uuid())
user_id String
tag String
auth_user AuthUser @relation(references: [id], fields: [user_id], onDelete: Cascade)
@@unique([user_id, tag], name: "user_id_tag") // <-- this is the unique constraint
@@index([user_id])
@@map("likes")
}
Then I was able to upsert via the following:
prisma.likes.upsert({
where: {
user_id_tag: { // <-- And this bit is important
user_id: user.userId,
tag: tag.tag
}
},
update: {},
create: tag
})
The fields in where need to be unique.
If you can make some field, let's say date @unique (date: DateTime! @unique), and use that for your where in the upsert, I think it would work (tested on my local)