For the model, it can be simplified as follows as Prisma supports @updatedAt which will automatically update the column:
model Post {
author String @id
lastUpdated DateTime @updatedAt
categories Category[]
}
model Category {
id Int @id
posts Post[]
}
As for the query, it would look like this:
const categories = [
{ create: { id: 1 }, where: { id: 1 } },
{ create: { id: 2 }, where: { id: 2 } },
]
await db.post.upsert({
where: { author: 'author' },
create: {
author: 'author',
categories: {
connectOrCreate: categories,
},
},
update: {
categories: { connectOrCreate: categories },
},
})
connectOrCreate will create if not present and add the categories to the posts as well.
Answer from Ryan on Stack Overflowhow to create or update many-to-many relation?
mysql - Create or update one to many relationship in Prisma - Stack Overflow
How to connect to more than one relation using Prisma Client upsert function? - Stack Overflow
Upserting a document and nesting an upsert of a one-to-many relation using a key that is created when the parent document is created?
I'm providing my solution based on the clarifications you provided in the comments. First I would make the following changes to your Schema.
Changing the schema
model A_User {
id Int @id
username String
age Int
bio String @db.VarChar(1000)
createdOn DateTime @default(now())
features A_Features[]
}
model A_Features {
id Int @id @default(autoincrement())
description String @unique
users A_User[]
}
Notably, the relationship between A_User and A_Features is now many-to-many. So a single A_Features record can be connected to many A_User records (as well as the opposite).
Additionally, A_Features.description is now unique, so it's possible to uniquely search for a certain feature using just it's description.
You can read the Prisma Guide on Relations to learn more about many-to-many relations.
Writing the update query
Again, based on the clarification you provided in the comments, the update operation will do the following:
Overwrite existing
featuresin aA_Userrecord. So any previousfeatureswill be disconnected and replaced with the newly provided ones. Note that the previousfeatureswill not be deleted fromA_Featurestable, but they will simply be disconnected from theA_User.featuresrelation.Create the newly provided features that do not yet exist in the
A_Featurestable, and Connect the provided features that already exist in theA_Featurestable.
You can perform this operation using two separate update queries. The first update will Disconnect all previously connected features for the provided A_User. The second query will Connect or Create the newly provided features in the A_Features table. Finally, you can use the transactions API to ensure that both operations happen in order and together. The transactions API will ensure that if there is an error in any one of the two updates, then both will fail and be rolled back by the database.
//inside async function
const disconnectPreviouslyConnectedFeatures = prisma.a_User.update({
where: {id: 1},
data: {
features: {
set: [] // disconnecting all previous features
}
}
})
const connectOrCreateNewFeatures = prisma.a_User.update({
where: {id: 1},
data: {
features: {
// connect or create the new features
connectOrCreate: [
{
where: {
description: "'first feature'"
}, create: {
description: "'first feature'"
}
},
{
where: {
description: "second feature"
}, create: {
description: "second feature"
}
}
]
}
}
})
// transaction to ensure either BOTH operations happen or NONE of them happen.
await prisma.$transaction([disconnectPreviouslyConnectedFeatures, connectOrCreateNewFeatures ])
If you want a better idea of how connect, disconnect and connectOrCreate works, read the Nested Writes section of the Prisma Relation queries article in the docs.
The TypeScript definitions of prisma.a_User.update can tell you exactly what options it takes. That will tell you why the 'features' does not exist in type error is occurring. I imagine the object you're passing to data takes a different set of options than you are specifying; if you can inspect the TypeScript types, Prisma will tell you exactly what options are available.
If you're trying to add new features, and update specific ones, you would need to specify how Prisma can find an old feature (if it exists) to update that one. Upsert won't work in the way that you're currently using it; you need to provide some kind of identifier to the upsert call in order to figure out if the feature you're adding already exists.
https://www.prisma.io/docs/reference/api-reference/prisma-client-reference/#upsert
You need at least create (what data to pass if the feature does NOT exist), update (what data to pass if the feature DOES exist), and where (how Prisma can find the feature that you want to update or create.)
You also need to call upsert multiple times; one for each feature you're looking to update or create. You can batch the calls together with Promise.all in that case.
const upsertFeature1Promise = prisma.a_User.update({
data: {
// upsert call goes here, with "create", "update", and "where"
}
});
const upsertFeature2Promise = prisma.a_User.update({
data: {
// upsert call goes here, with "create", "update", and "where"
}
});
const [results1, results2] = await Promise.all([
upsertFeaturePromise1,
upsertFeaturePromise2
]);
Hello all, I am creating a web app in NextJS and I'm using the Prisma ORM. I have a user table that has a foreign key to a status table in a one to many relationship. I am implementing the functionality to update the status on a user account but I'm having difficulties. The following is the code snippet I'm using:
const user = await db.user.update({
where: {
id,
},
data: {
status: {
connect: {
id: statusId,
},
},
},
});I get the following error:
error - PrismaClientValidationError:
Invalid `prisma.user.update()` invocation:
{
where: {
id: 'cl706mhjt0006kouzjrzd2kf9'
},
data: {
status: {
~~~~~~
connect: {
id: '3'
}
}
}
}
Unknown arg `status` in data.status for type UserUncheckedUpdateInput. Did you mean `statusId`?I also get the same error if I try to change the statusId field. I'm probably doing something dumb.. Thanks in advance.
EDIT: This has been solved.
First thing, you don't need to use the connect method to update the relation on the table. While it works, it's easier just to update the statusId directly.
Second, the error was actually due to a type mismatch. The id being passed as it turns out was a string. The way I parsed and sent my forms from the frontend to the backend converted the type into that string. After doing a parseInt on the id it resolved my error and worked correctly.