How to update a many to many relationship in Prisma? - many-to-many

I am modelling a boxing tournament.
Boxers and Fights have a many-to-many relationship:
A Boxer has many Fights
A Fight has many Boxers (exactly 2)
Here are the models in the schema
model Fight {
id Int #id #default(autoincrement())
name String
boxers BoxerFights[]
}
model Boxer {
id Int #id #default(autoincrement())
name String #unique
fights BoxerFights[]
}
model BoxerFights {
boxer Boxer #relation(fields: [boxerId], references: [id])
boxerId Int
fight Fight #relation(fields: [fightId], references: [id])
fightId Int
##id([boxerId, fightId])
}
When creating a boxer I use the fight's name and the 2 boxer ids:
const fight = await prisma.fight.create({
data: {
name,
boxers: {
createMany: {
data: [
{
boxerId: boxerId1,
},
{
boxerId: boxerId2,
},
],
},
},
},
})
How would I update the fight if a boxer needed to be changed? Something like this? I'm not sure if I use update and set
const fight = await prisma.fight.update({
data: {
name: newName,
boxers: {
set: {
data: [
{
boxerId: newBoxerId1,
},
{
boxerId: newBoxerId2,
},
],
},
},
},
})

Here you go an example how to do that:
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const saveData = async () => {
const boxer1 = await prisma.boxer.create({
data: {
name: 'Boxer1',
},
})
const boxer2 = await prisma.boxer.create({
data: {
name: 'Boxer2',
},
})
const fight = await prisma.fight.create({
data: {
name: 'Fight 1',
boxers: {
createMany: {
data: [
{ boxerId: boxer1.id },
{ boxerId: boxer2.id },
]
},
}
},
select: {
id: true,
name: true,
boxers: {
select: {
boxer: {
select: {
name: true,
}
}
}
}
}
})
console.log(JSON.stringify(fight, null, 2))
const boxer3 = await prisma.boxer.create({
data: {
name: 'Boxer3',
},
})
const fightUpdated = await prisma.fight.update({
where: {
id: fight.id
},
data: {
boxers: {
createMany: {
data: [
{ boxerId: boxer3.id },
]
},
deleteMany: {
OR: [
{ boxerId: { equals: boxer1.id } },
]
}
}
},
select: {
name: true,
boxers: {
select: {
boxer: {
select: {
name: true,
}
}
}
}
}
})
console.log(JSON.stringify(fightUpdated, null, 2))
}
saveData()
In the update you have to remove the previous boxer and the new one :)

Related

How to delete a record and any relationship records in an explicit many to many relationship?

I'm struggling to find documentation for handling explicit many to many relationships in Prisma. So I have resorted to dev by Stackoverflow....
I have a many to many relationship:
model Fight {
id Int #id #default(autoincrement())
name String
fighters FighterFights[]
}
model Fighter {
id Int #id #default(autoincrement())
name String #unique
fights FighterFights[]
}
model FighterFights {
fighter Fighter #relation(fields: [fighterId], references: [id])
fighterId Int
fight Fight #relation(fields: [fightId], references: [id])
fightId Int
##id([fighterId, fightId])
}
I am trying to delete a fight and delete the relationship in FighterFights but not delete the actual fighter.
I tried the following:
const result = await prisma.fight.delete({
where: {
id: Number(id),
},
})
but get the error:
PrismaClientKnownRequestError:
Invalid `prisma.fight.delete()` invocation:
Foreign key constraint failed on the field: `FighterFights_fightId_fkey (index)`
I then also tried:
const result = await prisma.fight.delete({
where: { id: Number(id) },
data: {
fighterFights: {
deleteMany: {
where: { fightId: id },
},
},
},
})
But I get the error:
PrismaClientValidationError:
Invalid `prisma.fight.delete()` invocation:
{
where: {
id: 1
},
data: {
~~~~
fighterFights: {
deleteMany: {
where: {
fightId: '1'
}
}
}
}
}
Unknown arg `data` in data for type Fight. Available args:
type deleteOneFight {
where: FightWhereUniqueInput
}
I also tried:
const result = await prisma.fight.delete({
where: {
id: Number(id),
},
data: {
fighterFights: {
deleteMany: [{ fightId: { equals: Number(id) } }],
},
},
})
but get the error:
Invalid `prisma.fight.delete()` invocation:
{
where: {
id: 1
},
data: {
~~~~
fighterFights: {
deleteMany: [
{
fightId: {
equals: 1
}
}
]
}
}
}
Unknown arg `data` in data for type Fight. Available args:
type deleteOneFight {
where: FightWhereUniqueInput
}
Here is the Prisma documentation to disconnect related fields
For single disconnect
const updatePost = await prisma.user.update({
where: {
id: 16,
},
data: {
posts: {
disconnect: [{ id: 12 }, { id: 19 }],
},
},
select: {
posts: true,
},
})
To disconnect all
const updateUser = await prisma.user.update({
where: {
id: 16
},
data: {
posts: {
set: []
}
},
include: {
posts: true
}
})
here you go a way to do that:
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const saveData = async () => {
const fighter1 = await prisma.fighter.create({
data: {
name: 'Ryu',
},
})
const fighter2 = await prisma.fighter.create({
data: {
name: 'Ken',
},
})
console.log('FIGHTERS');
console.log(JSON.stringify(fighter1, null, 2));
console.log(JSON.stringify(fighter2, null, 2));
const fight = await prisma.fight.create({
data: {
name: 'Ryu vs Ken',
fighters: {
createMany: {
data: [
{
fighterId: fighter1.id,
},
{
fighterId: fighter2.id,
},
]
},
},
},
select: {
id: true,
fighters: {
select: {
fighter: true,
},
},
},
});
console.log('FIGHTS');
console.log(JSON.stringify(await prisma.fight.findMany({ include: { fighters: true } }), null, 2));
const fighterFightsToDelete = prisma.fighterFights.deleteMany({
where: {
fightId: fight.id,
}
})
const fightToDelete = prisma.fight.delete({
where: {
id: fight.id,
}
})
await prisma.$transaction([ fighterFightsToDelete, fightToDelete ])
console.log('RESULT');
console.log(JSON.stringify(await prisma.fight.findMany({ include: { fighters: true } }), null, 2));
console.log(JSON.stringify(await prisma.fighter.findMany({ include: { fights: true } }), null, 2));
}
saveData()
And the result is the following :)

How to add Sequelize Association into Model

I am new to Typescript and trying to connect with the Mysql database I have created the following files
User.ts
export const UserData = sequelize.define('users', {
id: {
type:Sequelize.INTEGER,
autoIncrement:true,
allowNull:false,
primaryKey:true
},
name: {
type:Sequelize.STRING,
allowNull:false
},
address: {
type:Sequelize.INTEGER,
allowNull:false
}
});
Address.ts
export const CityData = sequelize.define('city_data', {
id: {
type:Sequelize.INTEGER,
autoIncrement:true,
allowNull:false,
primaryKey:true
},
city: {
type:Sequelize.STRING,
allowNull:false
},
house_no: {
type:Sequelize.INTEGER,
allowNull:false
}});
here I want to add hasMany association on User model user hasMany => address[] How can I achieve that?
what I am looking here how to use sequelize in typescript how to create setup and save data into tables ?
Thank you in advance
users.hasMany(city_data, {
foreignKey: "address",
});
Or
UserData.hasMany(CityData, {
foreignKey: "address",
});
how to add :
const UserData = sequelize.define('users', {
id: {
type:Sequelize.INTEGER,
autoIncrement:true,
allowNull:false,
primaryKey:true
},
name: {
type:Sequelize.STRING,
allowNull:false
},
address: {
type:Sequelize.INTEGER,
allowNull:false
}
});
UserData.hasMany(city_data, {
foreignKey: "address",
});
export UserData;

One to many relationship in sequelize with MYSQL

I have two tables:
const attr = {
name: {
type: DataTypes.STRING,
},
};
const Tags = createModel('Tags', attr, {});
and:
const attr = {
tagId: {
type: DataTypes.INTEGER,
references: { model: 'Tags', key: 'id' },
}
}
const Client = createModel('Client', attr, {})
Client.belongsTo(Tag, { foreignKey: 'tagId', as: 'tags' });
and my query is this:
const clientCount = await Client.findAll({
include: [ { model: Tags, as: 'tags' } ],
attributes: { exclude: 'tagId' }
});
and this is my response:
{
"id": 1,
"createdAt": "2020-01-20T00:00:00.000Z",
"updatedAt": "2020-01-22T00:00:00.000Z",
"tags": {
"id": 1,
"name": "New tag",
"createdAt": "2020-01-20T00:00:00.000Z",
"updatedAt": "2020-01-20T00:00:00.000Z"
}
}
but I want my tags to be an array, so I guest I have to define a one to many association, but everything I tried so far failed.
What I want is tags to be an array, where I can add multiple tag objects:
{
"id": 1,
"createdAt": "2020-01-20T00:00:00.000Z",
"updatedAt": "2020-01-22T00:00:00.000Z",
"tags": [
{
"id": 1,
"name": "New tag",
"createdAt": "2020-01-20T00:00:00.000Z",
"updatedAt": "2020-01-20T00:00:00.000Z"
}
]
}
Method1
We need new model as Client_Tag
const attr = {
clientId: {
type: DataTypes.INTEGER,
},
tagId: {
type: DataTypes.INTEGER,
},
};
const Client_Tag = createModel('Client_Tag', attr, {});
Client.belongsToMany(Tag, {
foreignKey: 'clientId',
otherKey: 'tagId',
through: models.Client_Tag,
as: 'tags'
});
const clientCount = await Client.findAll({
include: [ { model: Tags, as: 'tags' } ],
attributes: { exclude: 'tagId' }
});
Method2
const attr = {
name: {
type: DataTypes.STRING,
},
clientId: { // need clientId in tag model, and remove 'tagId' from client model
type: DataTypes.INTEGER,
}
};
const Tags = createModel('Tags', attr, {});
Client.belongsToMany(Tag, { foreignKey: 'tagId', as: 'tags' });

GraphQL - operating elements of array

I would like to display some information about members, but I don't know how to resolve array of field 'time'. This is array, because it shows their login time. What should I do?
I used GraphQLString, but I am aware of this bad solution.
So I'm getting an error:
"message": "String cannot represent value: [\"12:08\"]",
Here is schema.js
const axios = require("axios");
const {
GraphQLObjectType,
GraphQLString,
GraphQLList,
GraphQLSchema
} = require("graphql");
const memberType = new GraphQLObjectType({
name: "Member",
fields: () => ({
nick: {
type: GraphQLString
},
name_and_surname: {
type: GraphQLString
},
time: {
type: GraphQLString
}
})
});
//Root Query
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
users: {
type: new GraphQLList(memberType),
description: "List of members",
resolve(parent, args) {
return axios
.get("http://25.98.140.121:5000/data")
.then(res => res.data);
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
});
And here is JSON
[
{
"time": [
"12:08"
],
"nick": "Cogi12",
"name_and_surname: "John Steps"
},
{
"time": [
"12:16"
],
"nick": "haris22",
"name_and_surname": "Kenny Jobs"
},
{
"time": [
"12:07",
"12:08",
"12:17",
"12:19",
"12:45",
"13:25"
],
"nick": "Wonski",
"name_and_surname": "Mathew Oxford"
}
]
you can use GraphQLList along with GraphQLString for time type like this,
const memberType = new GraphQLObjectType({
name: "Member",
fields: () => ({
nick: {
type: GraphQLString
},
name_and_surname: {
type: GraphQLString
},
time: {
type: new GraphQLList(GraphQLString)
}
})
});

Custom type in GraphQL mutation

I am using GraphQL js.I want to implement One-to-many association in it.I have two types user and Office.One user has many offices.
userType:
var graphql = require('graphql');
const userType = new graphql.GraphQLObjectType({
name: 'user',
fields :()=>{
var officeType=require('./officeSchema');
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
},
office:{
type:officeType
}
};
}
});
module.exports=userType;
officeSchema:
const officeType = new graphql.GraphQLObjectType({
name: 'office',
fields:()=> {
var userType = require('./userSchema');
return {
_id: {
type: graphql.GraphQLID
},
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
},
users: {
type: new graphql.GraphQLList(userType),
resolve: (obj,{_id}) => {
fetch('http://0.0.0.0:8082/office/user/'+obj._id, {
method: "GET",
headers: {
'Content-Type': 'application/json'
}
})
.then(function(res) {return res});
}
}
};
}
});
Now the mutation code is as follows:
const Adduser = {
type: userType,
args: {
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
}
},
resolve: (obj, {
input
}) => {
}
};
const Addoffice = {
type: OfficeType,
args: {
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
},
users: {
type: new graphql.GraphQLList(userInputType)
}
},
resolve: (obj, {
input
}) => {
}
};
const Rootmutation = new graphql.GraphQLObjectType({
name: 'Rootmutation',
fields: {
Adduser: Adduser,
Addoffice: Addoffice
}
});
This code is throwing error as
Rootmutation.Addoffice(users:) argument type must be Input Type but got: [user].
I want to add the actual fields in database as well as associated tables' fields but couldn't figure out the problem.
Updated:
1-Added GraphQLInputObjectType:
const officeInputType = new graphql.GraphQLInputObjectType({
name: 'officeinput',
fields: () => {
return {
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
}
}
}
});
const userInputType = new graphql.GraphQLInputObjectType({
name: 'userinput',
fields: () => {
return {
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
}
}
}
});
2-Added userinputtype instead of usertype in AddOffice.
Now the error is
Rootmutation.Addoffice(user:) argument type must be Input Type but got: userinput.
The problem is that you provided userType as one of the argument types for the Addoffice mutation. userType cannot be an argument type. Instead, you must use an input type.
There are two object types: output and input types. Your userType and officeType are output types. You need to create an input type using GraphQLInputObjectType [docs]. It will likely have very similar fields. You can use that as a type on your argument field.
const userInputType = new graphql.GraphQLInputObjectType({
name: 'UserInput',
fields () => {
return {
_id: {
type: graphql.GraphQLID
},
// ...
};
}
});