I really know that the problem Is with me and Prisma's one-to-many relationship is working alright but just bear with me please.
1. This is the model's part where I have the problem:
model Product{
Id Int #id #default(autoincrement())
Uuid String #unique #default(uuid())
Title String
BrandName String?
Thumbnails Thumbnail[] // one to many between thumbnail and Product
Price Float
DiscountRate Float?
Category Category #relation(fields: [CategoryId], references: [Id]) // one to many between Category and Product
CategoryId Int // The field containing the ID of the Category of this product
Status Status
Favorite Boolean #default(false)
Stock Int #default(0)
Item Item[] // one to many between Item and Product
}
model Cart{
Id Int #id #default(autoincrement())
Items Item[] // one to many between Item and Cart
}
model Item{
Id Int #id #default(autoincrement())
Product Product #relation(fields: [ProductId], references: [Id]) // one to many between Item and Product
ProductId Int
Quantity Int
Cart Cart? #relation(fields: [CartId],references: [Id]) // one to many between Cart and Item
CartId Int?
}
2. API Code (NextJs)
// addItem.js
import { PrismaClient } from "#prisma/client";
const prisma = new PrismaClient();
export default async (req, res) => {
let PrId = req.body.prodId;
let Qte = req.body.Qte;
let newItem = await prisma.item.create({
data:{
Quantity: Qte,
Product:{
connect:{
Id: PrId,
},
},
Cart:{
connect:{
Id: req.body.cartId
}
}
},
});
return res.status(200).json(newItem);
};
3. Problem's explanation:
Now the thing is that I have multiple carts in the database, each cart contains Items as shown in the model. The real problem is with creating new items:
Adding the first item goes smoothly.
When I wanna add another item which is connected to the same Product I get an error as follows:
Unique constraint failed on the constraint: `Item_ProductId_key`
at RequestHandler.handleRequestError (C:\Users\Bachar\Desktop\First_Freelance\node_modules\#prisma\client\runtime\index.js:30873:13)
at RequestHandler.request (C:\Users\Bachar\Desktop\First_Freelance\node_modules\#prisma\client\runtime\index.js:30856:12)
at async PrismaClient._request (C:\Users\Bachar\Desktop\First_Freelance\node_modules\#prisma\client\runtime\index.js:31836:16)
at async __WEBPACK_DEFAULT_EXPORT__ (webpack-internal:///(api)/./pages/api/addItem.js:12:19)
at async Object.apiResolver (C:\Users\Bachar\Desktop\First_Freelance\node_modules\next\dist\server\api-utils\node.js:367:9)
at async DevServer.runApi (C:\Users\Bachar\Desktop\First_Freelance\node_modules\next\dist\server\next-server.js:474:9)
at async Object.fn (C:\Users\Bachar\Desktop\First_Freelance\node_modules\next\dist\server\next-server.js:736:37)
at async Router.execute (C:\Users\Bachar\Desktop\First_Freelance\node_modules\next\dist\server\router.js:252:36)
at async DevServer.run (C:\Users\Bachar\Desktop\First_Freelance\node_modules\next\dist\server\base-server.js:381:29)
at async DevServer.run (C:\Users\Bachar\Desktop\First_Freelance\node_modules\next\dist\server\dev\next-dev-server.js:724:20) {
code: 'P2002',
clientVersion: '4.5.0',
meta: { target: 'Item_ProductId_key' },
page: '/api/addItem'
}
First of all thanks for anyone who viewed this.
I had a migration before the one above where the ProductId inside the Cart model flagged as #unique, Which I removed in this last migration. The problem was that the database wasn't in sync with this last Prisma Schema even after using npx prisma migrate dev.
I copied the schema file, removed the whole prisma folder, used the npx prisma init to generate a new folder then pasted the schema, migrated and voila!!
Anyways if anyone has an idea on how to do it without removing the schema file It would be a big help to tell me, cuz that would have been one hell of a day if the app was already in production.
Related
I am trying to query by passing in the name field but I get two different errors.
"Validation error of type MissingFieldArgument:
Missing field argument id # 'getBlog'"
"Validation error of type UnknownArgument:
Unknown field argument name # 'getBlog'"
I was able to successfully query it with the id field. Im new to graphql and im using this on my app that also uses aws amplify and aws appsync.
schema.graphql
type Blog #model {
id: ID!
name: String!
posts: [Post] #connection(keyName: "byBlog", fields: ["id"])
}
queries.ts
// this is an auto generated file. This will be overwritten
export const getBlog = /* GraphQL */ `
query GetBlog($name: String!) { //changed from ($id: ID!)
getBlog(name: $name) { //changed from (id: $id)
id
name
posts {
items {
id
title
blogID
createdAt
updatedAt
}
nextToken
}
createdAt
updatedAt
}
}
`;
app.tsx
const getRecord = async () => {
const result = await API.graphql(graphqlOperation(getBlog, {name: "testing"}))
console.log(result)
}
I also tried pushing it to aws amplify push but it detected no changes. I didnt expect it to as i didnt change anything in the schema, only the queries. thanks in advance
If you look at your GraphQL schema you should see the definition for the GetBlog query. It likely looks like:
query {
GetBlog(id: ID!): Blog
}
That particular query can only be queried by id. Assuming you have control of the server you should also be able to define a GetBlogByName query:
query {
GetBlogByName(name: String): Blog
}
But then it will be up to you to ensure that name is unique or deal with potentially >1 response.
I´m doing an Spotify clone and I´m trying to add a song to a playlist but my query doesn't work, until this point, everything was good following the documentation on prisma docs, but I cannot do this query, every time get an error, so if someone can tell me, how can I do this with an example, I'll be very grateful.
My question is, having this schema, how can I add a song to a playlist? there are two models affected by the query, song (where i am trying to add) and playlist.
My schema:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
}
model User {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
email String #unique
firstName String
lastName String
password String
playlists Playlist[]
}
// here
model Song {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
name String
artist Artist #relation(fields: [artistId], references: [id])
artistId Int
playlists Playlist[]
duration Int
url String
}
model Artist {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
songs Song[]
name String #unique
}
// here
model Playlist {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
name String
songs Song[]
user User #relation(fields: [userId], references: [id])
userId Int
}
I am trying to add the song like this:
let songId = 1;
let playlistId = 1;
let lists;
// get the playlists the song is part of
lists = await prisma.song.findFirst({
select: {
playlists: true
},
where: {
id: +songId
}
})
// get the playlist data i need
const list = await prisma.playlist.findUnique({
where: {
id: playlistId
}
})
// create the array for update with the data
// plus the data I want to add
lists = [ ...lists.playlists, list ]
// trying to update the old array with the new data (lists)
// this is what i'm doing wrong, help please
await prisma.song.update({
where: { id: +songId },
data:{
playlists: lists
}
})
after many tries i finally got what i want if anyone knows a better way please tell me, i want to learn, for now this is my solution:
i need to send each value as id: playlistId
const song = await prisma.song.findUnique({
select: {
playlists: true
},
where: {
id: +songId
}
})
// get an array of objects, id: playlistId
const songPlaylistsIds = song.playlists.map( playlist => ({id: playlist.id}))
// I prepare the array with the content that already exists plus the new content that I want to add:
const playlists = [...songPlaylistsIds, { id: playlistId}]
await prisma.song.update({
where: { id: +songId },
data:{
playlists: {
// finally for each object in the array i get, id: playlistId and it works.
set: playlists.map( playlistSong => ({ ...playlistSong }))
}
}
})
Problems I had doing this: I was wrong in thinking that it should work as simple as playlist: lists I wanted to change the content to a new one but I couldn't, I needed to send the values one by one.
Another error when I get the content of the playlists. I had the full object but just needed to send the id.
And lastly, in the prisma documentation, there is a method like set, push, but this method doesn't work, at least I don't know how to make push work
I have an SqlLite database that contains these models
model Product {
id Int #id #unique(map: "sqlite_autoindex_products_1") #default(autoincrement())
label String
description String?
price Int
category_id Int
thumbnail_url String?
categories Category #relation("categoriesToproducts", fields: [category_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
##map("products")
}
model Category {
id Int #id #unique(map: "sqlite_autoindex_categories_1") #default(autoincrement())
index Int?
label String
description String?
products Product[] #relation("categoriesToproducts")
##map("categories")
}
I would like to get products list using :
async allProducts(): Promise<Product[] | null> {
return this.prisma.product.findMany();
}
It returns Products raw data with category_Id field.
I would like to know if there is a way to get category mapped data inside Category table instead of only the id field ?
I have a solution is to get Category table data than loop on products list then replace category_id with the category object.
But I would like to know if there is a better way to map directly data when making request via Prisma client.
In order to query a related model, you have to either use select or include.
prisma.product.findMany({
include: {
categories: true
}
})
// or
prisma.product.findMany({
select: {
categories: true
}
});
Useful documentation links
Relations
Relation queries
I am creating a basic crud api with nodejs and prisma. My Schema is as follows:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
}
model Category {
id String #unique #default(cuid())
title String
description String
products Product[]
}
model Product {
id String #unique #default(cuid())
title String
description String
price Float
createdAt DateTime #default(now())
updatedAt DateTime?
category Category? #relation(fields: [categoryId], references: [id])
categoryId String?
}
I am trying to make the products field in the Category model optional. But Prisma doesn't allow that. But I want my users to create a category even without creating a post or vice-versa. How can I get around this?
According to the Prisma documentation, lists cannot be optional: https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#remarks-5
However, the products field not being optional does not mean that it cannot be an empty when a new Category is created:
await prisma.category.create({
data: {
title: 'books',
description: 'books',
products: {},
}
})
Then you can create or connect the product later:
await prisma.category.update({
where: {
id: "category-id"
},
data: {
products: {
connect: {
id: "product-id"
}
}
}
})
I need help working through this error. I have a one-to many-self-relationship that dictates all the comments/children a post will have. see schema below.
model Post {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
description String
postedBy User? #relation(fields: [postedById], references: [id])
postedById Int?
votes Vote[]
comments Post[] #relation(name: "comment")
parent Post? #relation(name: "comment", fields: [parentId], references: [id])
parentId Int? #default(0)
}
As you can see, the parentId defaults to zero. I always want the root post to have a parentId of zero to signify that it is a root post because there is no Post with Id 0 for the foreign key to reference.
When I added the one-many-self-relationship with default 0 my prisma populated correctly, ignoring foreign-key errors in my db as seen below.
The parent field is null? or undefined? because the parentId = 0 doesn't exist. That is good because those are root posts. The problem is when I try and make a post mutation using gql I get a foreign key error because there is no post with id 0. See mutation below.
const { userId, prisma } = context;
if (userId === null) throw new Error("Not Authenticated");
const newPost = await prisma.post.create({
data: {
description: args.description,
postedBy: { connect: { id: userId } },
parent: { connect: { id: args.parentId } },
},
});
context.pubsub.publish("NEW_POST", newPost);
return newPost;
}
if I replace args.parentId = 0 I will get the foreign key error in gql, if args.parentId = 1 I will not get an error but the post is no longer considered a root post (bad).
can someone please offer me some guidance with this issue? I would like to ignore the foreign key error if possible.
I have looked into the referential actions (seen below) to set a default on post but I don't think my use case is the purpose of referential actions so I am not sure where to look...
model Post {
id Int #id #default(autoincrement())
title String
authorUsername String? #default("anonymous")
author User? #relation(fields: [authorUsername], references: [username], onUpdate: SetDefault)
}