Get all related models for Prisma many-to-many relation - prisma

I have the following Prisma schema:
model User {
id String #id #default(cuid())
name String?
email String? #unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
joinedEvents Event[]
eventParticiants EventParticiants[]
}
model Event {
id String #id #default(cuid())
title String
description String
code String
num_tasks Int
num_beacons Int
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
owner User #relation(fields: [ownerId], references: [id])
ownerId String
eventParticiants EventParticiants[]
tasks Tasks[]
beacons Beacons[]
}
model EventParticiants {
event Event #relation(fields: [eventId], references: [id])
eventId String
user User #relation(fields: [userId], references: [id])
userId String
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
##id([eventId, userId])
}
Each user can join multiple events and each event can be joined by multiple users. This is mediated by a middle table.
I would like to return all the events for a user but this does not seem to be working:
const events = await prisma.user.findMany({
where: { owner: { email: session.user.email } },
select: {
eventParticiants: {
}
},
orderBy: { createdAt: "desc" },
});

You need to add another level of select or include to go from eventParticipants to events:
const events = await prisma.user.findMany({
where: { owner: { email: session.user.email } },
select: {
eventParticiants: {
include: {
event: true
}
}
},
orderBy: { createdAt: "desc" },
});

Related

Can't create a nested many To many properties

I've been stuck on this problem for hours.
I'm trying to create an object linked by a many to many relationship.
However, I get this error when the function is invoked:
Unknown arg 0 in data.merchandises.create.0 for type ListingsMerchandisesCreateWithoutListingInput.
Argument merchandise for data.merchandises.create.merchandise is missing.
I don't know where that "0" comes from.
Thank you in advance for your help..
Full log of error:
Invalid `prisma[prismaModel].create()` invocation in
/app/node_modules/prisma-factory/dist/index.js:109:44
106 data = hooks.beforeCreate(data);
107 }
108 const prismaModel = (0, import_camel_case.camelCase)(modelName);
→ 109 let result = await prisma[prismaModel].create({
data: {
type: 'FOR_RENT',
name: 'consequatur',
merchandises: {
create: {
'0': {
merchandise: {
create: {
cosmetic: 'GOOD',
typology: 'NEW',
quantity: 76,
price: 80,
location: {
create: {
name: 'repellat',
line1: '600 Jerde Mews',
line2: 'Apt. 517',
line3: '79414 Lenore Harbor',
line4: 'placeat',
city: 'Port Astridshire',
postalCode: '47459-8067',
state: 'North Carolina',
country: 'Antigua and Barbuda',
other: 'iste'
}
},
user: {
create: {
email: 'Neoma41#gmail.com',
firstName: 'Casimir',
lastName: 'Kub'
}
},
product: {
create: {
name: 'Luxurious Steel Keyboard',
description: 'The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J',
barcode: 'r0h7w9h1d',
barcodeType: 'EAN13',
brand: 'Bespoke',
model: 'Countach',
lenght: 25,
width: 57,
weight: 11,
capacity: 62,
impactUnit: 'UNIT',
manufacturingImpact: 31,
destructiveImpact: 81
}
}
}
}
},
+ merchandise: {
+ create?: MerchandiseCreateWithoutListingsInput | MerchandiseUncheckedCreateWithoutListingsInput,
+ connectOrCreate?: MerchandiseCreateOrConnectWithoutListingsInput,
+ connect?: MerchandiseWhereUniqueInput
+ }
}
}
}
})
Unknown arg `0` in data.merchandises.create.0 for type ListingsMerchandisesCreateWithoutListingInput.
Argument merchandise for data.merchandises.create.merchandise is missing.
The factory:
import { createFactory } from 'prisma-factory';
import { faker } from '#faker-js/faker';
import {
BarcodeType,
Cosmetic,
ImpactUnit,
Listing,
ListingType,
Prisma,
Typology,
} from '#prisma/client';
const DEFAULT_ATTRIBUTES = {
type: ListingType.FOR_RENT,
name: faker.lorem.word(),
merchandises: {
create: [
{
merchandise: {
create: {
cosmetic: Cosmetic.GOOD,
typology: Typology.NEW,
quantity: Number(faker.random.numeric(2)),
price: Number(faker.random.numeric(2)),
location: {
create: {
name: faker.lorem.word(),
line1: faker.address.streetAddress(),
line2: faker.address.secondaryAddress(),
line3: faker.address.streetAddress(),
line4: faker.lorem.word(),
city: faker.address.city(),
postalCode: faker.address.zipCode(),
state: faker.address.state(),
country: faker.address.country(),
other: faker.lorem.word(4),
},
},
user: {
create: {
email: faker.internet.email(),
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
},
},
product: {
create: {
name: faker.commerce.productName(),
description: faker.commerce.productDescription(),
barcode: faker.random.alphaNumeric(9),
barcodeType: BarcodeType.EAN13,
brand: faker.commerce.productAdjective(),
model: faker.vehicle.model(),
lenght: Number(faker.random.numeric(2)),
width: Number(faker.random.numeric(2)),
weight: Number(faker.random.numeric(2)),
capacity: Number(faker.random.numeric(2)),
impactUnit: ImpactUnit.UNIT,
manufacturingImpact: Number(faker.random.numeric(2)),
destructiveImpact: Number(faker.random.numeric(2)),
},
},
},
},
},
],
},
};
export const ListingFactory = createFactory<Prisma.ListingCreateInput, Listing>(
'listing',
DEFAULT_ATTRIBUTES,
);
concerning schema:
model Listing {
id Int #id #default(autoincrement())
type ListingType
name String
merchandises ListingsMerchandises[]
availability Availability?
category Category? #relation(fields: [categoryId], references: [id])
categoryId Int?
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
deletedAt DateTime?
}
model Merchandise {
id Int #id #default(autoincrement())
cosmetic Cosmetic
typology Typology
quantity Int
price Int
productId Int
product Product #relation(fields: [productId], references: [id])
userId Int
user User #relation(fields: [userId], references: [id])
locationId Int
location Location? #relation(fields: [locationId], references: [id])
listings ListingsMerchandises[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
deletedAt DateTime?
}
model ListingsMerchandises {
listingId Int
listing Listing #relation(fields: [listingId], references: [id])
merchandiseId Int
merchandise Merchandise #relation(fields: [merchandiseId], references: [id])
##id([listingId, merchandiseId])
}
I tried several formats, I even tried a connect but without success.
No type errors are thrown

Prisma explicit many to many field already defined

I have comics which has many writers, artists and characters and i'm trying to join everything together in prisma, but struggling to understand what I'm doing wrong.
Comic schema:
model comics {
uniqueCoverId String #id
name String
artists comic_contributors[] #relation("artists")
writers comic_contributors[] #relation("writers")
}
Artists schema
model comic_artists {
id String #id #default(uuid())
name String?
comics comic_contributors[]
}
Writers schema
model comic_writers {
id String #id #default(uuid())
name String?
comics comic_contributors[]
}
Intermediary table
model comic_contributors {
writer_id String #unique
writer comic_writers? #relation("writers", fields: [writer_id], references: [id])
artist_id String #unique
artist comic_artists? #relation("artists", fields: [artist_id], references: [id])
##id([writer_id, artist_id])
}
When I try to format prisma it returns the errors
error: Field "comics" is already defined on model "comic_contributors".
comicsUniqueCoverId String?
comics comics? #relation(fields: [comicsUniqueCoverId], references: [uniqueCoverId])
error: Field "comicsUniqueCoverId" is already defined on model "comic_contributors".
comics comics? #relation(fields: [comicsUniqueCoverId], references: [uniqueCoverId])
comicsUniqueCoverId String?
Any suggestions on what I'm doing wrong please?
You don't need to explicit a many-to-many relationship table, Prisma is doing it for you!
Prisma implicit many-to-many
You only have to say:
model comics {
uniqueCoverId String #id
name String
artists comic_artists[]
writers comic_writers[]
}
model comic_artists {
id String #id #default(uuid())
name String?
comics comics[]
}
model comic_writers {
id String #id #default(uuid())
name String?
comics comics[]
}
and Prisma will create hidden relationship tables as
_comic_artitsTocomics
column A -> comic_artits.id
column B -> comics.uniqueCoverId
_comic_writersTocomics
column A -> comic_writers.id
column B -> comics.uniqueCoverId
This allow you to do
const comic = await prisma.comics.findUnique({
where: {
uniqueCoverId: 'UniqueCoverId',
},
include: {
artists: true,
writers: true,
},
});
And comic will looks like
{
uniqueCoverId: 'UniqueCoverId',
name: 'Name',
artists: [
{ id: '210059e6-00ab-448c-aea9-b706251ade52', name: 'Artist1' },
{ id: '38cd8efa-2a66-4fe5-ad47-ec4f511647c0', name: 'Artist2' },
{ id: '86d6c908-f17b-4fbd-b0ee-c314f06aeaa9', name: 'Artist3' }
],
writers: [
{ id: '9cf97bf4-9c43-4579-924b-15a7f5dcb3f9', name: 'Writer1' },
{ id: 'afe6eb2d-6d69-44f2-a491-14827dc94e66', name: 'Writer2' },
{ id: 'cdac61cf-339d-460d-960b-6581fa2d7a57', name: 'Writer3' }
]
}
Prisma explicit many-to-many
But if you really need an explicit many-to-many relationship to add some data on the relation it will looks like this schema
model comics {
uniqueCoverId String #id
name String
artists comic_artistsOncomics[]
writers comic_writersOncomics[]
}
model comic_artists {
id String #id #default(uuid())
name String?
comics comic_artistsOncomics[]
}
model comic_artistsOncomics {
uniqueCoverId String
comic comics #relation(fields: [uniqueCoverId], references: [uniqueCoverId])
artistId String
artist comic_artists #relation(fields: [artistId], references: [id])
// Some data
##id([uniqueCoverId, artistId])
}
model comic_writers {
id String #id #default(uuid())
name String?
comics comic_writersOncomics[]
}
model comic_writersOncomics {
uniqueCoverId String
comic comics #relation(fields: [uniqueCoverId], references: [uniqueCoverId])
writerId String
writer comic_writers #relation(fields: [writerId], references: [id])
// Some data
##id([uniqueCoverId, writerId])
}
The previous findUnique will now looks like
const test = await prisma.comics.findUnique({
where: {
uniqueCoverId: 'uniqueCoverId',
},
include: {
artists: {
include: {
artist: true,
},
},
writers: {
include: {
writer: true,
},
},
},
});
And the result
{
uniqueCoverId: "UniqueCoverId",
name: "Name",
artists: [
{
uniqueCoverId: "UniqueCoverId",
artistId: "210059e6-00ab-448c-aea9-b706251ade52",
artist: {
id: "210059e6-00ab-448c-aea9-b706251ade52",
name: "Artist1",
},
},
{
uniqueCoverId: "UniqueCoverId",
artistId: "38cd8efa-2a66-4fe5-ad47-ec4f511647c0",
artist: {
id: "38cd8efa-2a66-4fe5-ad47-ec4f511647c0",
name: "Artist2",
},
},
{
uniqueCoverId: "UniqueCoverId",
artistId: "86d6c908-f17b-4fbd-b0ee-c314f06aeaa9",
artist: {
id: "86d6c908-f17b-4fbd-b0ee-c314f06aeaa9",
name: "Artist3",
},
},
],
writers: [
{
uniqueCoverId: "UniqueCoverId",
writerId: "9cf97bf4-9c43-4579-924b-15a7f5dcb3f9",
writer: {
id: "9cf97bf4-9c43-4579-924b-15a7f5dcb3f9",
name: "Writer1",
},
},
{
uniqueCoverId: "UniqueCoverId",
writerId: "afe6eb2d-6d69-44f2-a491-14827dc94e66",
writer: {
id: "afe6eb2d-6d69-44f2-a491-14827dc94e66",
name: "Writer2",
},
},
{
uniqueCoverId: "UniqueCoverId",
writerId: "cdac61cf-339d-460d-960b-6581fa2d7a57",
writer: {
id: "cdac61cf-339d-460d-960b-6581fa2d7a57",
name: "Writer3",
},
},
],
}
EDIT FOR YOU TO TEST
model comics {
id String #id #default(uuid())
uniqueCoverId String #unique
name String
artists comic_artists[]
writers comic_writers[]
}
model comic_artists {
id String #id #default(uuid())
name String?
comics comics[]
}
model comic_writers {
id String #id #default(uuid())
name String?
comics comics[]
}

Prisma : Models and Relationship 1-n

I have two tables User and Tasks and a user can have many tasks, however i want a query to return a particular task, fetching details for the task, with author and assigned to users from the user table, usually would be done using aliases. DB is mysql - Thanks
//schema.prisma
model User {
id Int #id #default(autoincrement())
taskby Task[] #relation("taskBy")
taskto Task[] #relation("taskTo")
}
model Task {
id Int #id #default(autoincrement())
created_at DateTime #default(now())
updated_at DateTime #updatedAt
assigned_to_uid Int
assigned_by_uid Int
assigned_to User #relation("taskTo",fields: [assigned_to_uid], references: [id])
assigned_by User #relation("taskBy",fields: [assigned_by_uid], references: [id])
}
API:
if (id) {
res = await prisma.task.findUnique({
where: { id },
include: {
assigned_to: true
},
include: {
assigned_by: true
},
})
} else {...
Desired Response:
{
"id": 2,
"taskid": 2,
"assigned_to_uid": 1,
"assigned_by_uid": 2,
"assigned_by": {
"id": 2,
"firstName": "user2",
},
"assigned_to": {
"id": 1
"firstName": "user1",
},
}
You should be able to get the desired response by using the below query:
if (id) {
const response = await prisma.task.findUnique({
where: { id },
include: {
assigned_to: true,
assigned_by: true,
},
});
console.log(response);
}
Response for the above query:
{
id: 1,
created_at: 2022-02-28T07:22:06.917Z,
updated_at: 2022-02-28T07:22:06.918Z,
assigned_to_uid: 2,
assigned_by_uid: 1,
assigned_to: { id: 2, firstName: 'Jane', lastName: 'Doe' },
assigned_by: { id: 1, firstName: 'John', lastName: 'Doe' }
}

How to filter on relation in Prisma ORM

I am working currently on a course service. Users have the possibility to register and deregister for courses. The entire system is built in a microservice architecture, which means that users are managed by another service. Therefore, the data model of the course service looks like this:
model course {
id Int #id #default(autoincrement())
orderNumber Int #unique
courseNumber String #unique #db.VarChar(255)
courseName String #db.VarChar(255)
courseOfficer String #db.VarChar(255)
degree String #db.VarChar(255)
ectCount Int
faculty String #db.VarChar(255)
isWinter Boolean #default(false)
isSummer Boolean #default(false)
courseDescription String? #db.VarChar(255)
enrollmentCourse enrollmentCourse[]
}
model enrollmentCourse {
id Int #id #default(autoincrement())
userId String #db.VarChar(1024)
course course #relation(fields: [courseId], references: [id])
courseId Int
}
I want to find all the courses in which a certain user has enrolled.
I have written 2 queries. One goes over the courses and tries to filter on the enrollmentCourse. However, this one does not work and I get all the courses back. Whereas the second one goes over the enrollmentCourse and then uses a mapping to return the courses. This works, but I don't like this solution and would prefer the 1st query if it worked:
(I have used this guide in order to write the first query: here)
const result1 = await this.prisma.course.findMany({
where: { enrollmentCourse: { every: { userId: user.id } } },
include: { enrollmentCourse: true }
});
console.log('Test result 1: ');
console.log(result1);
const result2 = await this.prisma.enrollmentCourse.findMany({
where: { userId: user.id },
include: { course: { include: { enrollmentCourse: true } } }
});
console.log('Test result 2: ');
console.log(result2.map((enrollment) => enrollment.course));
If now the user is not enrolled in a course the result of both queries are:
Test result 1:
[
{
id: 2,
orderNumber: 1,
courseNumber: 'test123',
courseName: 'testcourse',
courseOfficer: 'testcontact',
degree: 'Bachelor',
ectCount: 5,
faculty: 'testfaculty',
isWinter: true,
isSummer: false,
courseDescription: 'test.pdf',
enrollmentCourse: []
}
]
Test result 2:
[]
If now the user has enrolled courses it looks like this:
Test result 1:
[
{
id: 2,
orderNumber: 1,
courseNumber: 'test123',
courseName: 'testcourse',
courseOfficer: 'testcontact',
degree: 'Bachelor',
ectCount: 5,
faculty: 'testfaculty',
isWinter: true,
isSummer: false,
courseDescription: 'test.pdf',
enrollmentCourse: [ [Object] ]
}
]
Test result 2:
[
{
id: 2,
orderNumber: 1,
courseNumber: 'test123',
courseName: 'testcourse',
courseOfficer: 'testcontact',
degree: 'Bachelor',
ectCount: 5,
faculty: 'testfaculty',
isWinter: true,
isSummer: false,
courseDescription: 'test.pdf',
enrollmentCourse: [ [Object] ]
}
]
As we can see the first query does not work correctly. Can anybody give me a hint? Is there anything that I'm missing?
As per the doc you mentioned, you need to use some instead of every as you need at least one user returned if it matches.
const result1 = await this.prisma.course.findMany({
where: { enrollmentCourse: { some: { userId: user.id } } },
include: { enrollmentCourse: true }
});
This should give all the courses where the user is registered

Updating a many-to-many relationship in Prisma

I'm trying to figure out the right way to implement an upsert/update of the following schema:
model Post {
author String #Id
lastUpdated DateTime #default(now())
categories Category[]
}
model Category {
id Int #id
posts Post[]
}
Here is what I'd like to do. Get a post with category ids attached to it and insert it into the schema above.
The following command appears to insert the post
const post = await prisma.post.upsert({
where:{
author: 'TK'
},
update:{
lastUpdated: new Date()
},
create: {
author: 'TK'
}
})
My challenge is how do I also upsert the Category. I'll be getting a list of Catogories in the like 1,2,3 and if they do not exist I need to insert it into the category table and add the post to it. If the category does exist, I need to update the record with the post I inserted above preserving all attached posts.
Would appreciate it if I could be pointed in the right direction.
For the model, it can be simplified as follows as Prisma supports #updatedAt which will automatically update the column:
model Post {
author String #id
lastUpdated DateTime #updatedAt
categories Category[]
}
model Category {
id Int #id
posts Post[]
}
As for the query, it would look like this:
const categories = [
{ create: { id: 1 }, where: { id: 1 } },
{ create: { id: 2 }, where: { id: 2 } },
]
await db.post.upsert({
where: { author: 'author' },
create: {
author: 'author',
categories: {
connectOrCreate: categories,
},
},
update: {
categories: { connectOrCreate: categories },
},
})
connectOrCreate will create if not present and add the categories to the posts as well.