Prisma exclude link table when fetching relation - javascript

Does anyone know if Prisma has a way to avoid unnecessary nesting levels when fetching nested objects through the link table?
Schema:
model User {
id String #id #default(cuid())
name String?
email String? #unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
roles UsersRoles[]
created_at DateTime #default(now())
}
model Role {
id Int #id #default(autoincrement())
name AllowedRoles #default(USER)
users UsersRoles[]
}
model UsersRoles {
userId String
user User #relation(fields: [userId], references: [id])
roleId Int
role Role #relation(fields: [roleId], references: [id])
##id([userId, roleId])
}
In the screenshot you see that I must do
include: {
roles: {
include: {
role: true
}
}
}
to get the role id and name, but I also get the unnecessary data from the link table/pivot table. Can I query the role data directly, without getting the pivot table in the result?
It works with Prisma implicit many to many relationships, but I want to do with explicit
Edit 1:
Found this https://www.prisma.io/docs/guides/database/troubleshooting-orm/help-articles/working-with-many-to-many-relations
Prisma shows an example how to get rid of link table data:
const result = posts.map((post) => {
return { ...post, tags: post.tags.map((tag) => tag.tag) }
})
I guess since even in Prisma docs they do it like this, there is no way to do so during fetching time with Prisma client. But I might be wrong.

Try swapping out your top-level include for a select. Prisma will return all scalar (non-relation) fields by default unless you specify a select object.
relevant docs

Related

How to soft delete a explicit many to many relation in prisma and what are the best practices in doing so

I want to implement soft delete in explicit many to many relation using prisma. I want to somehow disconnect the link betweeen them and mark both user and all its memories as deleted true.
is it a good approach ? or how to do this in genral
My Prisma Schema looks like this:
model User {
userId String #id #default(uuid())
memories UserMemory[]
deleted Boolean #default(false)
}
model Memory {
memoryId String #id #default(uuid())
users UserMemory[]
deleted Boolean #default(false)
}
model UserMemory {
userId String
user User? #relation(fields: [userId], references: [userId])
memoryId String
memory Memory? #relation(fields: [memoryId], references: [memoryId])
##id([userId, memoryId])

How to get Prisma client to generate relationship types

I am trying to create a one-to-many relationship between a user and posts. I can create the database schema and can write / query all ok but it appears the prisma client that is being generated doesn't have the relationships on the type.
For example, my schema looks like this:
model User {
id Int #id #default(autoincrement())
posts Post[]
}
model Post {
id Int #id #default(autoincrement())
author User #relation(fields: [authorId], references: [id])
authorId Int
}
I then run npx prisma generate which creates a client with the following types
/**
* Model User
*
*/
export type User = {
id: number
}
/**
* Model Post
*
*/
export type Post = {
id: number
authorId: number
}
I would expect the user type to look like this:
export type User = {
id: number;
posts: Post[];
}
Have I defined my Prisma schema correctly? What do I need to do to get the type to include the relation?
By default, a Prisma type will not include relational fields in the base "type". If you want to get the type of your User which includes related Posts, the Prisma client will include that based on the structure of your query.
https://www.prisma.io/docs/concepts/components/prisma-client/select-fields
You can use the include attribute on any Prisma CRUD operation to have the Prisma client return specific relational fields, AND those related fields are included in the emitted type. Prisma will take care of this typing for you!
const usersWithPosts = await prisma.user.findMany({
include: {
posts: true
}
});
// usersWithPosts has a type like this:
// Array<User & { posts: Array<Post> }>
========
EDIT: If you want to compute the type in advance without wanting to write a query, you can use Prisma.UserGetPayload (or some other form of GetPayload, as the prefix will change based on the model.)
type UserWithPosts = Prisma.UserGetPayload<{
include: {
posts: true;
};
}>;
This emits the following type:
type UserWithPosts = User & {
posts: Post[];
}

Relate existing User and Post in Prisma to create a favorites feature

I want a simple favorite feature. For that I need to connect an existing user with an existing post.
I cannot really find an explanation in the Prisma docs, they only show how to make relations when creating a new post.
Here is my schema:
model User {
uid String #id #default(uuid())
username String? #db.VarChar(24) #unique
favorites FavoritesOnUsers[]
model Post {
id Int #id #default(autoincrement())
title String #db.VarChar(255)
favoritedBy FavoritesOnUsers[]
}
model FavoritesOnUsers {
user User #relation(fields: [userId], references: [uid])
userId String
post Post #relation(fields: [postId], references: [id])
postId Int
##id([userId, postId])
}
So when the user likes a post and adds it to his favorites, how would such a query look like to combine the userId with the postId in the FavoritesOnUsers table?
Creating a record in the junction table should relate both entities:
await prisma.favouritesOnUsers.create({
data: { userId, postId },
});

Typescript + Prisma get object fields from express request

I want to get User's fields from a request body.
Below is my current solution, the reason I use : User is it mandates required fields to be destructed also it gives autocompletion.
const { username, password, email, birthday, country_code, preferences }: User = req.body;
I want to automatically get all fields from req.body. Maybe something like below.
const namedObject = ({} : User = req.body);
User Model
model User {
id Int #id #default(autoincrement())
username String #unique
email String #unique
password String
created_at DateTime #default(now())
birthday DateTime?
country_code String?
preferences Json?
Message Message[]
}
Question
What is the proper solution for this?

How to control sort direction in a list query in AWS-Amplify with GraphQL

I've seen several useful posts on how to create schemas in AWS-Amplify's GrahphQL API package that will return a sorted response. In brief, if you have the following in your schema.graphql file
type Record #model
#key(name: "byDateCreated", fields: ["status", "createdAt"], queryField: "RecordsByDateCreated") {
id: ID!
status: RecordStatus!
description: String!
createdAt: String
}
It will create a custom query called recordsByDateCreated. Using it as follows (js here, folks):
await API.graphql(graphqlOperation(recordsByDateCreated, { status: 'unused', limit: 10 }));
will return the first 10 records in the table sorted by their createdAt values. By default, this data will be returned in ascending order, which means that you'll get the oldest records first.
However, what I need is a response that has the newest records first. What do I have to add to in schema or my query so I can set the order of the sorting?
(Spoiler alert: I'm answering my own question here in case anyone else is looking for help with this.)
You would need a way to order the table's records in descending order. If you go and look at the file generated by AWS-Amplify you'll see that the new query you've created accepts a series of arguments:
export const recordsByDateCreated = /* GraphQL */ `
query RecordsByDateCreated(
$status: RecordStatus
$createdAt: ModelStringKeyConditionInput
$sortDirection: ModelSortDirection
$filter: ModelRecordFilterInput
$limit: Int
$nextToken: String
) {
RecordsByDateCreated(
status: $status
createdAt: $createdAt
sortDirection: $sortDirection
filter: $filter
limit: $limit
nextToken: $nextToken
) {
items {
id
description
status
createdAt
updatedAt
}
nextToken
}
}
`
It turns out that if you know what the possible values are for ModelSortDirection (they are are 'ASC' and 'DESC') you can pass one in as one of the variables arguments when you make that query like so:
await API.graphql(graphqlOperation(recordsByDateCreated, { status: 'unused', limit: 10, sortDirection: 'DESC' }));
(Note that the key for the variable you're passing is sortDirection and not $sortDirection, or ModelSortDirection.)
I couldn't find this in AWS-Amplify's docs and relied on other posts that I've found. If you've found any documentation relevant to this then maybe you could add a link in the comments.
(Can't comment with a reputation below 50 lol so need to make a whole other answer)
As you mentioned adding sortDirection as one of the variables arguments allows you to choose the direction, but also if you're looking to sort the items by a specific attribute other than the default one, you'll have to make that choice in the graphql schema model definition.
So for the model User you'd choose the attribute in the second key field
type User
#model
#key(fields: ["id", "DoB"]) {
id: ID!
name: String!
DoB: String!
createdAt: String!
}
and a query would sort the items by their DoB

Categories