Prisma 2.0 already has a Dataloader built in exactly for this purpose. This means your resolvers might do multiple calls to findOne but those will be batched into one big SQL query under the hood. So there should be no need for you to implement this optimization on your own.
How to reproduce a Prisma `include` statement for arrays of related entities without SQL?
How do I do a left join in Prisma?
How to insert and update element in array
mysql - LEFT JOINS and aggregation in a single Prisma query - Stack Overflow
Sorry for the seemingly stupid question, but I couldn't find an answer in the docs.
I have two tables in MySQL and I'm trying to left join them on a column. How do I do that?
Despite the accepted answer, the actual answer is: No.
For actual performant joins to work, they must solve an issue that's been open for about a year and a half as of writing this response: https://github.com/prisma/prisma/issues/5184
Currently, there is no way to join tables together. Queries that include relations only include the relational data by using separate queries.
Yes, this is possible with Prisma!. For making this work, you need to specify on your "schema.prisma" file how are models related with each other. That way, code generation will set the possible queries/operations.
Change it to this:
model Post {
id Int @id @unique @default(autoincrement()) @map("id")
userId Int @map("user_id")
movieId Int @unique @map("movie_id")
title String @map("title") @db.Text
description String? @map("description") @db.Text
tags Json? @map("tags")
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(0)
image String? @default("https://picsum.photos/400/600/?blur=10") @map("image") @db.VarChar(256)
year Int @map("year")
submittedBy String @map("submitted_by") @db.Text
tmdbRating Decimal? @default(0.0) @map("tmdb_rating") @db.Decimal(3, 1)
tmdbRatingCount Int? @default(0) @map("tmdb_rating_count")
ratings Rating[]
@@map("posts")
}
model Rating {
id Int @unique @default(autoincrement()) @map("id") @db.UnsignedInt
userId Int @map("user_id") @db.UnsignedInt
rating Int @default(0) @map("rating") @db.UnsignedTinyInt
entryId Int
entry Post @relation(fields: [entryId], references: [id])
createdAt DateTime @default(now()) @map("created_a") @db.DateTime(0)
updatedAt DateTime? @map("updated_a") @db.DateTime(0)
@@id([entryId, userId])
@@map("ratings")
}
Note: Please follow the naming conventions (singular form, PascalCase). I made those changes for you at the schema above. @@map allows you to set the name you use on your db tables.
Then, after generating the client, you will get access to the relational operations.
// All posts with ratings data
const postsWithRatings = await prisma.post.findMany({
include: {
// Here you can keep including data from other models
ratings: true
},
// you can also "select" specific properties
});
// Calculate on your API
const ratedPosts = postsWithRatings.map( post => {
const ratingsCount = post.ratings.length;
const ratingsTotal = post.ratings.reduce((acc, b) => acc + b.rating, 0)
return {
...post,
userRating: ratingsTotal / ratingsCount
}
})
// OR...
// Get avg from db
const averages = await prisma.rating.groupBy({
by: ["entryId"],
_avg: {
rating: true
},
orderBy: {
entryId: "desc"
}
})
// Get just posts
const posts = await prisma.post.findMany({
orderBy: {
id: "desc"
}
});
// then match the ratings with posts
const mappedRatings = posts.map( (post, idx) => {
return {
...post,
userRating: averages[idx]._avg.rating
}
})
You could also create a class with a method for making this easier. But I strongly recommend you to implement GraphQL on your API. That way, you can add a virtual field inside your post type. Any time a post is requested alone or in a list, the average will be calculated. In that same way, you would have the flexibility to request data from other models and the "JOINS" will get handled for you automatically.
Last but not least, if you ever want to do a lot of queries at the same time, you can take advantage of the Prisma transactions.
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 find a solution :
https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#add-new-related-records-to-an-existing-record
await prisma.song.update({
where: { id: +songId },
data:{
playlists:{
create:{
data:{ id: playlistId}
}
}
}
})