Prisma - How to point two fields to same model? - prisma

I'm having trouble conceptualizing how to handle this issue. I've pored through the Prisma docs and other SO questions, but they all seem to be slightly different from this situation.
I have two models:
model User {
id Int #id #default(autoincrement())
firstName String? #map("first_name")
lastName String? #map("last_name")
email String #unique
password String
role UserRole #default(value: USER)
image String? #map("image")
createdAt DateTime #default(now()) #map("created_at")
updatedAt DateTime #updatedAt #map("updated_at")
friends Friend[]
##map("users")
}
model Friend {
id Int #id #default(autoincrement())
inviteSentOn DateTime #map("invite_sent_on") #db.Timestamptz(1)
inviteAcceptedOn DateTime #map("invite_accepted_on") #db.Timestamptz(1)
userId Int #map("user_id")
friendId Int #map("friend_id")
createdAt DateTime #default(now()) #map("created_at")
updatedAt DateTime #updatedAt #map("updated_at")
user User #relation(fields: [userId], references: [id])
// friend User? #relation(name: "FriendFriend", fields: [friendId], references: [id])
##map("friends")
}
I want to be able to set up the relationships on the Friend model to both point towards the User model, however I receive errors such as Error validating field 'friend' in model 'Friend': The relation field 'friend' on Model 'Friend' is missing an opposite relation field on the model 'User'.
I've tried adding the name property to the #relation field, but start receiving errors about ambiguous relations being detected.
How do I go about setting these relations up correctly?

You just need to provide name to disambiguate relation, like that:
model User {
id Int #id #default(autoincrement())
friend Friend?
friends Friend[] #relation(name: "friends")
}
model Friend {
id Int #id #default(autoincrement())
userId Int
friendId Int
user User #relation(fields: [userId], references: [id])
friend User #relation(fields: [friendId], references: [id], name: "friends")
}
And dont forget that both sides of relations need to have connections to the other.

Related

Does Prisma create a new relationship collection when using MongoDB?

Looking at the Prisma docs and they show the example below. In this instance, if I'm using MongoDB and define my schema as per below, does Prisma create a collection for me called _CategoryToPost on my behalf to record the many to many relationships?
Or do I have to create my own collection to document this relationship?
model User {
id Int #id #default(autoincrement())
email String #unique
name String?
role Role #default(USER)
posts Post[]
profile Profile?
}
model Profile {
id Int #id #default(autoincrement())
bio String
user User #relation(fields: [userId], references: [id])
userId Int #unique
}
model Post {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
title String
published Boolean #default(false)
author User #relation(fields: [authorId], references: [id])
authorId Int
categories Category[] #relation(references: [id])
}
model Category {
id Int #id #default(autoincrement())
name String
posts Post[] #relation(references: [id])
}
enum Role {
USER
ADMIN
}
Link to docs
Prisma will create the necessary collections when you run the npx prisma db push command. You should not need to worry about the underlying structure beyond that.

Prisma One-to-one relation issue

I have just recently started using prisma and I ran into an issue with relations. I have a user model and an address model.
model User {
id Int #id #unique #default(autoincrement())
username String
}
model Address {
id Int #id #unique #default(autoincrement())
street String
}
I need to add 2 addresses to the user: invoicing address and delivery address. In the address I don't need a user reference.
I thought this would work without issues by adding this to the user model:
invoiceAddress Address? #relation(name: "iAddress", fields: [iAddressId], references: [id])
deliveryAddress Address? #relation(name: "dAddress", fields: [dAddressId], references: [id])
iAddressId Int?
dAddressId Int?
But when saving the schema two user fields are added to the address model... which I don't need and now I have issues because they reference the same user model so I have to also name them and add scalar field...
Am I missing something??? This should be a basic use case imo.
This is a requirement from Prisma's end that relation fields should exist on both sides of the model, you cannot define relation field on only one model.
The following schema model should solve the issue for you:
model User {
id Int #id #unique #default(autoincrement())
username String
invoiceAddress Address? #relation(name: "iAddress", fields: [iAddressId], references: [id])
deliveryAddress Address? #relation(name: "dAddress", fields: [dAddressId], references: [id])
iAddressId Int?
dAddressId Int?
}
model Address {
id Int #id #unique #default(autoincrement())
street String
UserInvoice User[] #relation(name: "iAddress")
UserDelivery User[] #relation(name: "dAddress")
}
Please note that relation fields do not exist on database so UserInvoice and UserDelivery columns would not exist on Address table. Similarly invoiceAddress and deliveryAddress columns would not exist on User table.

One-to-many and may-to-many relation between two prisma model

I am working on a side project and I came to an issue that I'm not sure how to solve. I have created two models, one for User and one for Project. The relation between them is many-to-many, as many users can have many projects, but i would also like to add a createdBy to the Project model, and this should be one-to-one as each project can only have one user who creates it. This is how my models are looking:
model User {
id String #id #default(cuid())
name String?
email String? #unique
emailVerified DateTime?
image String?
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
accounts Account[]
sessions Session[]
projects Project[]
Project Project[] #relation("userId")
}
model Project {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
name String
favourite Boolean #default(false)
archived Boolean #default(false)
users User[]
about String?
archivedAt String?
deletedAt String?
createdBy User #relation("userId", fields: [userId], references: [id])
userId String
}
The error that is getting from prisma migrate dev is
Step 1 Added the required column userId to the Project table without a default value. There are 2 rows in this table, it is not possible to execute this step.
Not sure what I am doing wrong as am pretty much a db modeling novice. Any help would be appreciated.
To achieve Many-to-Many with One-To-Many you need to set your schema.prisma file like:
model User {
id String #id #default(cuid())
name String?
email String? #unique
emailVerified DateTime?
image String?
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
projects Project[]
userProjects UserProjects[]
}
model Project {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
name String
favourite Boolean #default(false)
archived Boolean #default(false)
about String?
archivedAt String?
deletedAt String?
createdBy User #relation(fields: [user_id], references: [id])
user_id String
projectUsers UserProjects[]
}
model UserProjects {
project Project #relation(fields: [project_id], references: [id])
project_id Int
user User #relation(fields: [user_id], references: [id])
user_id String
##id([project_id, user_id])
}
It should migrate successfully.

prisma2 how to relate one-to-many and many-to-one?

I need some help to understqnd how to set my data modelisation.
What i'm trying to do is :
Reference a group ID in User model. A user can only be in one group, this is what i've done below.
Reference in Group Model all users that are inside a group. This is what I need help with.
model User {
id String #id #default(uuid())
email String #unique
role Role #default(USER)
group Group? #relation(fields: [group_id], references: [id], onDelete: SetNull)
group_id String
created_at DateTime #default(now())
updated_at DateTime #updatedAt
##map("user")
}
model Group {
id String #id #default(uuid())
name String
users User[]
created_at DateTime #default(now())
updated_at DateTime #updatedAt
deleted Boolean #default(false)
##map("group")
}
How can I make this list of User when I already have users User[] for the relation in User model ?
(BTW i've read the doc but i'm totally lost...)
I think your code is correct, you can use prisma-client to test
This is an example of this relation
model Agents {
id Int #id #default(autoincrement()) #db.UnsignedInt
name String? #db.VarChar(255)
owner String? #db.VarChar(255)
address String? #db.Text
lat String? #db.VarChar(10)
lng String? #db.VarChar(10)
tel String? #db.VarChar(13)
mobile String? #db.VarChar(11)
workTime String? #db.VarChar(255)
province Provinces #relation(fields: [provinceId], references: [id])
provinceId Int #db.UnsignedInt
createDateTime DateTime #default(now()) #db.Timestamp(0)
updateDateTime DateTime? #db.Timestamp(0)
##index([provinceId], name: "provinceId")
##map(name: "agents")
}
model Provinces {
id Int #id #default(autoincrement()) #db.UnsignedInt
name String? #db.VarChar(255)
coords String? #db.Text
createDateTime DateTime #default(now()) #db.Timestamp(0)
updateDateTime DateTime? #db.Timestamp(0)
agents Agents[]
##map(name: "provinces")
}

Error validating: This line is not a valid field or attribute definition

I wonder why my model (the Like-model) does not work as I expect it to.
Maybe someone can explain?
model User {
id Int #id #default(autoincrement())
likes Like[]
}
model Like {
fromUser User #relation(fields: [fromUserId] references: [id])
fromUserId Int
toUser User #relation(fields: [toUserId] references: [id])
toUserId Int
##id([fromUserId, toUserId])
}
The error reads: Error validating: This line is not a valid field or attribute definition.
It points at fromUser User #relation(fields: [fromUserId] references: [id]) and toUser User #relation(fields: [toUserId] references: [id]).
You would need to model your relations in the following manner:
model User {
id Int #id #default(autoincrement())
likedUsers Like[] #relation("likedUsers")
usersWhoLiked Like[] #relation("usersWhoLiked")
}
model Like {
id Int #id #default(autoincrement())
likedUser User? #relation("likedUsers", fields: [likedUserId], references: [id])
likedUserId Int?
userWhoLiked User? #relation("usersWhoLiked", fields: [userWhoLikedId], references: [id])
userWhoLikedId Int?
}
Whenever you have more than 1 relation to a model you need to provide a relation name to disambiguate the relation.
Also you need to store which users you have liked and who liked the current user. So you would need two relations for this.
Missing commas.
The solution might look like this:
model User {
id Int #id #default(autoincrement())
likes Like[]
}
model Like {
fromUser User #relation(fields: [fromUserId], references: [id])
fromUserId Int
toUser User #relation(fields: [toUserId], references: [id])
toUserId Int
##id([fromUserId, toUserId])
}