Search code examples
many-to-manyprisma

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
}

Solution

  • 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 :)

    enter image description here