I have a Problem using Prisma where I want to findMany with a specific order.
My Model looks like this
model Item {
id Int #id #default(autoincrement())
title String
categoryId Int
category Category #relation(fields: [categoryId], references: [id])
}
model Category {
id Int #id #default(autoincrement())
title String
parentId Int?
parent Category? #relation("categoryRelation", fields: [parentId], references: [id], onDelete: NoAction, onUpdate: NoAction)
subCategories Category[] #relation("categoryRelation")
items Item[]
}
now I want to sort my items by category.parentId but if they dont have a parentId, I want to sort by categoryId. In raw sql I could use something like orderBy coalesce(c.parentId, categoryId)
but I would like to use the prisma way to solve this if there is one
Related
I have a model called "Setup"
model Setup {
id String #id #default(auto()) #map("_id") #db.ObjectId
userId String? #unique #db.ObjectId
user User? #relation(fields: [userId], references: [id])
contract String[]
legal String[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
In this model i want to store an array like
const contractData = {
id: '729a4839f3dapob44zt2b4b1',
name: 'Example Name',
text: 'Example Text'
}
so in my above model "Setup" i want to store the contractData
prisma.setup.create({
data: {
userId: '6399bc74426f71f2da6e316c',
personal: [],
contract: contractData,
legal: []
}
})
Unfortunately, this not work.
How can i define an Object for contract and store this in my database?
If you want to store a raw JSON, check out this guide: https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields
You will want to use the Json in Prisma in order to be able to store a raw JSON object (or multiple JSON objects as an array.)
model Setup {
id String #id #default(auto()) #map("_id") #db.ObjectId
userId String? #unique #db.ObjectId
user User? #relation(fields: [userId], references: [id])
contract Json[]
legal String[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
Your Prisma prisma.setup.create query would basically be the exact same. Note that querying for what's in this JSON will be trickier - I would recommend creating a new model and then connecting it to the Setup model, but that if that isn't an option you can still perform some limited queries on the contract field.
Docs: https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filter-on-a-json-field
In order to store an object in the contract field, you will need to change the type of the contract field from String[] to Object[].
model Setup {
id String #id #default(auto()) #map("_id") #db.ObjectId
userId String? #unique #db.ObjectId
user User? #relation(fields: [userId], references: [id])
contract Object[]
legal String[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
store an object in the contract field like
prisma.setup.create({
data: {
userId: '6399bc74426f71f2da6e316c',
personal: [],
contract: [contractData],
legal: []
}
})
contract field is now an array, so you will need to pass the object as an element of the array, like [contractData]
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.
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"
}
}
}
})