Using explicit Many to Many Relation in Prisma - many-to-many

I have the following User and Group models that share a many-to-many relation:
model User {
id String #id #default(uuid())
email String #unique
groups UsersGroups[]
##map("user")
}
model Group {
id String #id #default(uuid())
name String
users UsersGroups[]
##map("group")
}
model UsersGroups {
user User #relation(fields: [userId], references: [id])
userId String #map(name: "user_id")
group Group #relation(fields: [groupId], references: [id])
groupId String #map(name: "group_id")
##id([userId, groupId])
##map("users_groups")
}
I'm having trouble using the connect API in Prisma to connect the users and groups. Here's what I have:
await prisma.group.update({
where: {
id: groupId,
},
data: {
users: {
connect: users.map((user) => ({ id: user.id })),
},
},
include: { users: true },
});
That doesn't work and here is the error I'm getting in the console:
PrismaClientValidationError:
Invalid `prisma.group.update()` invocation:
{
where: {
id: '64ce24c7-3054-42f2-b49f-4cdb52cf1bc7'
},
data: {
users: {
connect: [
{
id: '0b3f4a51-0efe-4b0a-8763-e71bc8091b86'
~~
}
]
}
},
include: {
users: true
}
}
Unknown arg `id` in data.users.connect.0.id for type UsersGroupsWhereUniqueInput. Available args:
type UsersGroupsWhereUniqueInput {
userId_groupId?: UsersGroupsUserIdGroupIdCompoundUniqueInput
}
From that above, it looks as though it's attempting to connect a user with id: '0b3f4a51-0efe-4b0a-8763-e71bc8091b86' (which is a user that exists) to the group with id: '64ce24c7-3054-42f2-b49f-4cdb52cf1bc7' (which also exists).
I'd be very grateful if someone could point out where I'm going wrong as I've been going in circles with this for a while now...

You are using an explicit many-to-many relation, cf. https://www.prisma.io/docs/concepts/components/prisma-schema/relations/many-to-many-relations#explicit-many-to-many-relations
I.e. you have defined the model UsersGroups yourself.
As a consequence, you would have to manage/create the records in this table yourself and connect it with the entry in the third table, e.g. like this (haven't tested it):
prisma.group.update({
where: {
id: groupId,
},
data: {
users: { create: { user: { connect: { id: userId } } } },
},
include: { users: true },
});
or if you want to loop over an list:
prisma.group.update({
where: {
id: groupId,
},
data: {
users: {
create: users.map((user) => ({
user: { connect: { id: user.id } },
})),
},
},
include: { users: true },
});
I would suggest to replace groups UsersGroups[] and users UserGroups[] with
userGroups UsersGroups[] in the schema to make it clearer.
As an alternative to explicit relationships you could try to use implicit many-to-many relations in the schema like this:
model User {
id String #id #default(uuid())
email String #unique
groups Group[]
##map("user")
}
model Group {
id String #id #default(uuid())
name String
users User[]
##map("group")
}
cf. https://www.prisma.io/docs/concepts/components/prisma-schema/relations/many-to-many-relations#implicit-many-to-many-relations

Related

Prisma Many-to-Many relations with findMany (select)

I am facing an error with Prisma, it does not recognize my request which seems quite simple to me. I need to use "select" to retrieve only certain fields from the table.
Post model:
model Post {
id String #id #default(cuid())
title String
createdAt DateTime? #default(now())
categories CategoriesOnPosts[]
keywords KeywordsOnPosts[]
##map("posts")
}
Category model:
model Category {
id String #id #default(cuid())
name String
createdAt DateTime? #default(now())
posts CategoriesOnPosts[]
##map("categories")
}
CategoriesOnPosts model:
model CategoriesOnPosts {
postId String
categoryId String
post Post #relation(fields: [postId], references: [id])
category Category #relation(fields: [categoryId], references: [id])
##id([postId, categoryId])
##map("categoriesPosts")
}
My Prisma query:
export const getPosts = async () =>
await prisma.post.findMany({
select: {
id: true,
title: true,
categories: {
select: {
name: true,
slug: true,
},
},
createdAt: true,
},
orderBy: [
{
createdAt: 'desc',
},
],
});
I get the following error and I don't know how to fix it.
Unknown field categories for select statement on model Post.
Available options are listed in green.

Prisma Nodejs, relation with ids to get the name

im in trouble to find a way to make this, i want in "serieName" the name of the serie, but always return de id, i dont know what i need to do to make this relation correct, im trying to find a solution, but nothing works.
this is my models:
in Series model, i have a name, and in Figures_table i made a relation with him, and i want to get only the name when i pass the id for the field, so if Series have id: 1, name: "something", i want to show "something" not the id, but only show id.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Series {
id Int #unique #default(autoincrement())
serie String
Figures_table Figures_table[]
}
model Manufacturers {
id String #unique
manufacturer String
Figures_table Figures_table[]
}
model Figures_table {
id String #unique
name String #db.LongText
category String #db.LongText
price String #db.LongText
specifications String #db.LongText
releaseInfo String #db.LongText
details String #db.LongText
serieName Int
manufacturerName String #db.VarChar(191)
createdAt DateTime #default(now())
manufacturer Manufacturers #relation(fields: [manufacturerName], references: [id])
series Series #relation(fields: [serieName], references: [id])
Images Images[]
}
model Images {
id Int #unique #default(autoincrement())
link String
figureID String
figureReferenceID Figures_table #relation(fields: [figureID], references: [id])
}
Here's a script which would include the name of the Series while fetching a record from the figures_table
import { PrismaClient, Prisma } from '#prisma/client';
const prisma = new PrismaClient({
log: ['query', 'info', 'warn'],
});
async function main() {
await prisma.figures_table.create({
data: {
category: 'Figures Table Category',
details: 'Figures Table Details',
name: 'Figures Table Name',
id: '1',
price: '1',
releaseInfo: 'Figures Table Release Info',
specifications: 'Figures Table Specifications',
series: {
create: {
serie: 'Series 1',
},
},
manufacturer: {
create: {
manufacturer: 'Manufacturer 1',
id: '1',
},
},
},
});
const figures_table = await prisma.figures_table.findUnique({
where: {
id: '1',
},
include: {
series: true,
},
});
console.log(figures_table);
}
main()
.catch((e) => {
throw e;
})
.finally(async () => {
await prisma.$disconnect();
});
We used the include section to get the details of Series relation.
Response:
{
id: '1',
name: 'Figures Table Name',
category: 'Figures Table Category',
price: '1',
specifications: 'Figures Table Specifications',
releaseInfo: 'Figures Table Release Info',
details: 'Figures Table Details',
serieName: 1,
manufacturerName: '1',
createdAt: 2022-10-11T12:33:37.768Z,
series: { id: 1, serie: 'Series 1' }
}

Prisma - Unique constraint failed, while there is no unique field in schema

I am using prisma with three models,
model User {
id String #id #default(cuid())
name String #unique #db.VarChar(35)
email String #unique #db.VarChar(512)
password String #db.VarChar(1024)
details String #default("") #db.VarChar(512)
avatar String #default("/default-avatar.svg") #db.VarChar(150)
activity String #default("Online") #db.VarChar(25)
likes Int #default(0)
suggestions Boolean #default(false)
verified Boolean #default(false)
blockedUsers BlockedUser[]
comments Comment[]
communities Community[]
communityMembers CommunityMember[]
followers Follower[]
friends Friend[]
messages Message[]
posts Post[]
openDMs DM[]
interests UserInterest[]
##map("user")
}
model Community {
id String #id #default(cuid())
title String #unique #db.VarChar(35)
details String #db.VarChar(512)
memberID String?
membersUser User[]
members CommunityMember[]
interests CommunityInterest[]
posts Post[]
##map("community")
}
model CommunityMember {
id String #id #default(cuid())
nickname String?
userID String
communityID String
user User #relation(fields: [userID], references: [id])
community Community #relation(fields: [communityID], references: [id])
owner Boolean
##map("community_member")
}
I have a route in my backend that causes the problem. It creates a new community member table with prisma client and connects the existing user and community to itself, with their ids.
When I do this, I get an error: Unique constraint failed on the constraint: community_member_communityID_key
Here is the code with the creation of the community member:
await prisma.communityMember.create({
data: {
nickname: response.account.name,
user: {
connect: { id: response.account.id }
},
community: {
connect: { id: communityID }
},
owner: false
}
});
I have tried dropping the database and resetting the prisma migrations, with no luck.
When I view the table in mysql, it is apparent that the communityID and userID fields are set as unique, so I think this problem has to do with prisma migrate.
Does anybody know what's happening, and how I can successfully create these fields without them being unique?
Why are you using connect? According to documentation
https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#nested-writes
In nested writes you should use create:
await prisma.communityMember.create({
data: {
nickname: response.account.name,
user: {
create: [
{id: response.account.id}
]
},
community: {
create: [
{id: communityID}
]
},
owner: false
}
})

Sails / WaterLine ORM / Has Many Through: Insert data into join table

I'm newbie with Sails/WaterLine ORM
I'm following http://sailsjs.org/documentation/concepts/models-and-orm/associations/through-associations
One question.
How way to insert data into a join table ?
For example: User m - m Pet
User model
module.exports = {
attributes: {
name: {
type: 'string'
},
pets:{
collection: 'pet',
via: 'owner',
through: 'petuser'
}
}
Pet model
module.exports = {
attributes: {
name: {
type: 'string'
},
color: {
type: 'string'
},
owners:{
collection: 'user',
via: 'pet',
through: 'petuser'
}
}
PetUser model (join table)
module.exports = {
attributes: {
owner:{
model:'user'
},
pet: {
model: 'pet'
}
}
}
Pet data is available (some record with ID1, ID2, ID3...)
I want to add new one user with some pets
PetUser ( id , id_of_user, id_of_pet)
1, U1, P1
2, U1, P2
{
"name" : "John",
"pets" : [2,3]
}
UserController
module.exports = {
addUserWithPets: function(req, res) {
User.create(req.body).exec(function(err, user) {
if(err){
throw err;
}else {
/*pets.forEach(function(pet, index){
user.pets.add(pet);
})
user.save(function(err) {});*/
user.pets.add(data);
user.save(function(err) {});
}
return res.ok({
data: user
});
})
}
};
Thanks!
I think this hasn't been implemented yet in sails.
Refer to this question: through associations in sails.js on SO.
Here is what waterline docs say:
Many-to-Many through associations behave the same way as many-to-many associations with the exception of the join table being automatically created for you. This allows you to attach additional attributes onto the relationship inside of the join table.
Coming Soon

Populating one to many relationship in sails js without using primary key

Every example code of one to many in sails/waterline documentation assumes the primary key is the association between two models (I think).
http://sailsjs.org/documentation/concepts/models-and-orm/associations/one-to-many
However i have models that have a referral column that references some other values similar to
User
{
id (primary): <int>
email: <string>
}
recordings
{
id (primary): <int>
email: <that email from user>
}
atm im trying
userModel.js
{
attributes: {
email: {
type: 'string',
size: 255,
unique: true
},
},
queries: {
columnName: 'email',
model: 'recordings'
}
.....
}
}
recordingsModel.js
{
attributes: {
email: {
type: 'string',
size: 255,
},
},
queries: {
model: 'user'
}
.....
}
}
and in the Controller
sails.models.user
.find()
.populate('queries')
.exec(function (err, results) {
});
But i get the error
: ER_BAD_FIELD_ERROR: Unknown column '__queries.queries' in 'field list'
Does anyone have a good tutorial for one to many relationships in waterline because the documentation on there site is pretty bad so i feel im just not understanding how to design the models.
From what I can gather, what you want is to be able to set up your userModel and recordingsModel models such that, by giving a recording a certain value for email, it will automatically be associated with any users that share that email. This is not something that the Waterline (the Sails ORM) supports.
Instead, your best option is to set the models up as indicated in the documentation:
// userModel.js
{
attributes: {
email: {
type: 'string',
size: 255,
unique: true
},
},
recordings: {
collection: 'recordingsModel',
via: 'user'
}
.....
}
}
// recordingsModel.js
{
attributes: {
email: {
type: 'string',
size: 255,
},
},
user: {
model: 'userModel'
}
}
}
My guess is that you're trying to avoid having to look up a user ID in order to associate a new recording with it. You can do this if you make email the primary key of the userModel; then when you create a new recording, you can set its user to an email address and voila: the two are linked.