How to connect a many to many relationship using Prisma - prisma

I am trying to create and connect a record in a Prisma many to many relationship, but the connection part is not working for me.
Here are my Prisma models:
model Ingredient {
id Int #id #default(autoincrement())
name String
createdAt DateTime #default(now())
calories Int
protein Int
fat Int
carbs Int
netCarbs Int
metricQuantity Int
metricUnit String
imperialQuantity Int
imperialUnit String
recipes IngredientsOnRecipes[]
categories CategoriesOnIngredients[]
}
model IngredientCategory {
id Int #id #default(autoincrement())
name String
ingredients CategoriesOnIngredients[]
}
model CategoriesOnIngredients {
ingredient Ingredient #relation(fields: [ingredientId], references: [id])
ingredientId Int // relation scalar field (used in the `#relation` attribute above)
ingredientCategory IngredientCategory #relation(fields: [ingredientCategoryId], references: [id])
ingredientCategoryId Int // relation scalar field (used in the `#relation` attribute above)
assignedAt DateTime #default(now())
##id([ingredientId, ingredientCategoryId])
}
Here is the primsa query I am running:
const ingredient = await prisma.ingredient.create({
data: {
name: title,
metricQuantity: parseInt(quantityMetric),
metricUnit: unitMetric,
imperialQuantity: parseInt(quantityImperial),
imperialUnit: unitImperial,
calories: parseInt(calories),
netCarbs: parseInt(netCarbs),
carbs: parseInt(carbs),
protein: parseInt(protein),
fat: parseInt(fat),
categories: {
ingredientcategory: {
connect: { id: parseInt(categoryId) },
},
},
},
});
Creating a new ingredient works perfectly, but when I add this section:
categories: {
ingredientcategory: {
connect: { id: parseInt(categoryId) },
},
},
I get the following error:
Unknown arg ingredientcategory in data.categories.ingredientcategory for type CategoriesOnIngredientsCreateNestedManyWithoutIngredientInput. Did you mean createMany? Available args:
type CategoriesOnIngredientsCreateNestedManyWithoutIngredientInput {
create?: CategoriesOnIngredientsCreateWithoutIngredientInput | List | CategoriesOnIngredientsUncheckedCreateWithoutIngredientInput | List
connectOrCreate?: CategoriesOnIngredientsCreateOrConnectWithoutIngredientInput | List
createMany?: CategoriesOnIngredientsCreateManyIngredientInputEnvelope
connect?: CategoriesOnIngredientsWhereUniqueInput | List
}

You can try executing the following:
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const saveData = async () => {
const ingredient = await prisma.ingredient.create({
data: {
name: 'ingredient1',
categories: {
create: {
ingredientCategory: {
create: {
name: 'category1',
},
}
}
},
},
select: {
id: true,
name: true,
categories: {
select: {
ingredientId: true,
ingredientCategory: true,
}
},
},
});
console.log(JSON.stringify(ingredient, null, 2));
}
saveData()
And you will have the following:

I managed to get it to work, I had missed create:{} from my Prisma query.
const ingredient = await prisma.ingredient.create({
data: {
name: title,
metricQuantity: parseInt(quantityMetric),
metricUnit: unitMetric,
imperialQuantity: parseInt(quantityImperial),
imperialUnit: unitImperial,
calories: parseInt(calories),
netCarbs: parseInt(netCarbs),
carbs: parseInt(carbs),
protein: parseInt(protein),
fat: parseInt(fat),
categories: {
create: {
ingredientCategory: {
connect: { id: parseInt(categoryId) },
},
},
},
},
});

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

How to connect to more than one relation using Prisma Client upsert function?

When I'm trying to connect more than one relation to my Profile table I get the following error message:
PrismaClientValidationError:
Invalid `prisma.connection.upsert()` invocation:
{
where: {
id: ''
},
update: {
userOneId: 'clbcb6z58000gyb31ez95frvh',
userTwoId: 'clbcaz4bl000ayb31icwpzphu',
isUserOneApproved: false,
isUserTwoApproved: true,
connectionRequestedOnDate: '2022-12-07T21:48:12.441Z',
connectionAcceptedOnDate: undefined
},
create: {
userOneId: 'clbcb6z58000gyb31ez95frvh',
~~~~~~~~~~~~~
userTwoId: 'clbcaz4bl000ayb31icwpzphu',
~~~~~~~~
isUserOneApproved: false,
isUserTwoApproved: true,
connectionRequestedOnDate: '2022-12-07T21:48:12.441Z',
connectionAcceptedOnDate: undefined,
userOne: {
connect: {
id: 'clbcb6z58000gyb31ez95frvh'
}
},
userTwo: {
connect: {
id: 'clbcaz4bl000ayb31icwpzphu'
}
},
profile: {
connect: {
id: 'clbcb71l2000kyb31cclk79z3'
}
}
}
}
Unknown arg `userOneId` in create.userOneId for type ConnectionCreateInput. Did you mean `userOne`? Available args:
type ConnectionCreateInput {
id?: String
isUserOneApproved: Boolean
isUserTwoApproved: Boolean
connectionRequestedOnDate?: DateTime | Null
connectionAcceptedOnDate?: DateTime | Null
userOne: ProfileCreateNestedOneWithoutUserOneInput
userTwo: ProfileCreateNestedOneWithoutUserTwoInput
profile: ProfileCreateNestedOneWithoutConnectionInput
}
Unknown arg `userTwoId` in create.userTwoId for type ConnectionCreateInput. Did you mean `userTwo`? Available args:
type ConnectionCreateInput {
id?: String
isUserOneApproved: Boolean
isUserTwoApproved: Boolean
connectionRequestedOnDate?: DateTime | Null
connectionAcceptedOnDate?: DateTime | Null
userOne: ProfileCreateNestedOneWithoutUserOneInput
userTwo: ProfileCreateNestedOneWithoutUserTwoInput
profile: ProfileCreateNestedOneWithoutConnectionInput
}
This is how my prisma upsert function is currently defined:
const createOrUpdateRole = await prisma.connection.upsert({
where: { id: id },
update: {
userOneId: userOneId,
userTwoId: userTwoId,
isUserOneApproved,
isUserTwoApproved,
connectionRequestedOnDate,
connectionAcceptedOnDate,
},
create: {
userOneId: userOneId,
userTwoId: userTwoId,
isUserOneApproved,
isUserTwoApproved,
connectionRequestedOnDate,
connectionAcceptedOnDate,
userOne: { connect: { id: userOneId } },
userTwo: { connect: { id: userTwoId } },
profile: { connect: { id: profileId } },
},
});
My expectation when running the function was to connect userOne and userTwo to my Profile table using their respective ids. The reason for that was that I could then query for the connection and then read the profile data for userOne and userTwo.
This is my models defined in schema.prisma:
model Profile {
id String #id #default(cuid())
firstName String?
lastName String?
image String? #db.Text
userId String
user User #relation(fields: [userId], references: [id], onDelete: Cascade)
sensitive Sensitive[]
userOne Connection[] #relation("userOne")
userTwo Connection[] #relation("userTwo")
connection Connection[] #relation("profile")
##index([userId])
}
model Connection {
id String #id #default(cuid())
isUserOneApproved Boolean
isUserTwoApproved Boolean
connectionRequestedOnDate DateTime?
connectionAcceptedOnDate DateTime?
userOneId String
userOne Profile #relation("userOne", fields: [userOneId], references: [id], onDelete: Cascade)
userTwoId String
userTwo Profile #relation("userTwo", fields: [userTwoId], references: [id], onDelete: Cascade)
profileId String
profile Profile #relation("profile", fields: [profileId], references: [id], onDelete: Cascade)
##index([userOneId])
##index([userTwoId])
##index([profileId])
}
If I decide to one connect to only one of them, for instance userOneId using userOne: { connect: { id: userOneId } }, then the function runs as expected, but as soon as I start to define more than one I get the error mentioned above. What have I missed?
The error is pretty self-descriptive:
Unknown arg `userOneId` in create.userOneId for type ConnectionCreateInput
Since you are already passing userOne: {connect: {id: '.....' } } in your Prisma operation, you do not (and should not) also pass userOneId. You just need userOne: {connect..... and userTwo: {connect......
Your operation will end up looking like this:
const createOrUpdateRole = await prisma.connection.upsert({
where: {
id: id
},
update: {
// You can have __either__ `userOneId: 'value'` or `userOne: {connect....` here
// but not both
userOneId: userOneId,
userTwoId: userTwoId,
isUserOneApproved,
isUserTwoApproved,
connectionRequestedOnDate,
connectionAcceptedOnDate,
},
create: {
isUserOneApproved,
isUserTwoApproved,
connectionRequestedOnDate,
connectionAcceptedOnDate,
userOne: {
connect: {
id: userOneId
}
},
userTwo: {
connect: {
id: userTwoId
}
},
profile: {
connect: {
id: profileId
}
},
},
});

Prisma Client Select query on existence of value in joined table via Schema

In my instance i have a schema joining bonuses to a casino. query works great for data but I am unable to filter via the query itself. The where clause I used appears to be correct but I get an error the stating Object literal may only specify known properties, and 'nodeposit' does not exist in type. But I can query that data.
const data = await prisma.casino_p_casinos.findMany({
where: {
approved: 1,
rogue: 0,
bonuses: {
nodeposit: { gt : 0 },
}
},
select: {
id: true,
clean_name: true,
casino: true,
button: true,
bonuses: {
where: {
nodeposit: { gt: 0 },
},
},
},
take: 14,
});
If I remove the bonus pard in the WHERE clause the query works as expected but I want to grab all bonuses for each casino, but only if the bonuses contains a nodeposit value.
This nis what I want to use.
const data = await prisma.casino_p_casinos.findMany({
where: {
approved: 1,
rogue: 0,
bonuses: {
nodeposit: { gt : 0 },
},
},
select: {
id: true,
clean_name: true,
casino: true,
button: true,
bonuses: true,
},
take: 14,
});
SCHEMA :
model casino_p_casinos {
id Int #id #default(autoincrement())
casino String?
type String?
url String?
bonuses casino_p_bonus[]
model casino_p_bonus {
id Int #id #default(autoincrement())
parent Int
game String?
freespins Int?
freeplay String?
nodeposit Int?
deposit Int?
casino_p_casinos casino_p_casinos #relation(fields: [parent], references: [id])
}
You have a one to many relation, so when you add a where clause, you have one more layer with some, every or none like
const data = await prisma.casino_p_casinos.findMany({
where: {
approved: 1,
rogue: 0,
bonuses: {
// 'some' can be replaced by 'every' or 'none' here
some: {
nodeposit: { gt: 0 }
}
}
},
select: {
id: true,
clean_name: true,
casino: true,
button: true,
bonuses: true
},
take: 14
})
This query will filter casinos where some nodeposit are greater than 0 and return all bonuses, even those who are equals to 0.
And then, if you only want bonuses with nodeposit greater than 0 in casinos that have some, you should do:
const data = await prisma.casino_p_casinos.findMany({
where: {
approved: 1,
rogue: 0,
bonuses: {
// 'some' can be replaced by 'every' or 'none' here
some: {
nodeposit: { gt: 0 }
}
}
},
select: {
id: true,
clean_name: true,
casino: true,
button: true,
bonuses: {
where: {
nodeposit: { gt: 0 }
}
}
},
take: 14
})

Conditional query Prisma assigning a value using date

I want to find the menus type provided by the restaurant (breakfast type) according to the time now, and the hours to display is on ShowingHours model
I created a Menu model
model Menu {
id String #id #default(cuid())
type String?
branchId String
branch Branch #relation(fields: [branchId], references: [id])
menuCategories MenuCategory[]
ShowingHours ShowingHours? #relation(fields: [showingHoursId], references: [id])
showingHoursId String?
}
and ShowingHours
model ShowingHours {
id String #id #default(cuid())
fromHour Int?
fromMinute Int?
toHour Int?
toMinute Int?
allDay Boolean
menus Menu[]
}
let timeNow = new Date().getHours();
I want to make a condition that if the value of timeNow for example is 9 am, then query a menu that has a inbetween timenow hours from "fromHour" to "toHour"
My approach:
let menuType = await db.menu.findMany({
// between fromhour tohour
where: {
branchId: branchId,
//I WOULD LIKE TO MAKE A CONDITION LIKE: if timeNow >= fromHour && timenow < toHour then fetch
ShowingHours: {
OR: [
{
fromHour: {
in:
}
}
]
}
},
})
You can use the lt and gt comparison operators to form the query.
It could look something like this:
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient({
log: [{ level: 'query', emit: 'stdout' }],
});
async function main() {
let timeNow = new Date().getHours();
await prisma.menu.findMany({
where: {
branchId: '1',
ShowingHours: {
AND: [
{
fromHour: {
lt: timeNow,
},
},
{
toHour: {
gt: timeNow,
},
},
],
},
},
});
}
main()
.catch((e) => {
throw e;
})
.finally(async () => {
await prisma.$disconnect();
});

findUnique query returns null for array fields

I read the Prisma Relations documentation and it fixed my findMany query which is able to return valid data but I'm getting inconsistent results with findUnique.
Schema
model User {
id Int #id #default(autoincrement())
fname String
lname String
email String
password String
vehicles Vehicle[]
}
model Vehicle {
id Int #id #default(autoincrement())
vin String #unique
model String
make String
drivers User[]
}
Typedefs
const typeDefs = gql'
type User {
id: ID!
fname: String
lname: String
email: String
password: String
vehicles: [Vehicle]
}
type Vehicle {
id: ID!
vin: String
model: String
make: String
drivers: [User]
}
type Mutation {
post(id: ID!, fname: String!, lname: String!): User
}
type Query {
users: [User]
user(id: ID!): User
vehicles: [Vehicle]
vehicle(vin: String): Vehicle
}
'
This one works
users: async (_, __, context) => {
return context.prisma.user.findMany({
include: { vehicles: true}
})
},
However, for some reason the findUnique version will not resolve the array field for "vehicles"
This one doesn't work
user: async (_, args, context) => {
const id = +args.id
return context.prisma.user.findUnique({ where: {id} },
include: { vehicles: true}
)
},
This is what it returns
{
"data": {
"user": {
"id": "1",
"fname": "Jess",
"lname": "Potato",
"vehicles": null
}
}
}
I was reading about fragments and trying to find documentation on graphql resolvers but I haven't found anything relevant that can solve this issue.
Any insight would be appreciated! Thanks!
You need to fix the arguments passed to findUnique. Notice the arrangement of the { and }.
Change
return context.prisma.user.findUnique({ where: { id } },
// ^
include: { vehicles: true}
)
to
return context.prisma.user.findUnique({
where: { id },
include: { vehicles: true }
})