Skip to content

Instantly share code, notes, and snippets.

@dthyresson
Last active December 30, 2020 05:47
Show Gist options
  • Save dthyresson/520b71871958c4a31d4dadd053f03890 to your computer and use it in GitHub Desktop.
Save dthyresson/520b71871958c4a31d4dadd053f03890 to your computer and use it in GitHub Desktop.
Many to Many Nested Writes in Prisma and RedwoodJS

This gist is in response to a RedwoodJS Discord question from Andrew (HH):

How do I create a worker with many skills?

Andrew (HH)12/11/2020

export const createWorker = ({ input }) => {
  return db.worker.create({
    data: {
      ...input,
      skills: {
        // skillIds === [1,2,3]
        connect: input.skillIds.map((skillId) => ({ id: skillId }))
      }
    }
  })
}

I got the following error:
Unknown arg skills in data.skills for type WorkerUncheckedCreateInput.`

Andrew (HH)12/11/2020
I'm able to add skills after I've created the worker by using a separate db.worker.update but I wonder can I do it in the create function?

Use connect with existing Skills and create new Worker with some of these Skills

Given the Prisma schema:

datasource DS {
  // optionally set multiple providers
  // example: provider = ["sqlite", "postgresql"]
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

generator client {
  provider      = "prisma-client-js"
  binaryTargets = "native"
}

model Skill {
  id      Int      @id @default(autoincrement())
  name    String   @unique
  workers Worker[]
}

model Worker {
  id     Int     @id @default(autoincrement())
  name   String  @unique
  skills Skill[]
}

The following seeds will create and then connect Skills to new Workers:

/* eslint-disable no-console */
const { PrismaClient } = require('@prisma/client')
const dotenv = require('dotenv')

dotenv.config()
const db = new PrismaClient()

async function main() {
  console.log('Create Skill')

  const nunchuk = await db.skill.create({
    data: { name: 'Nunchuk' },
  })

  const bow = await db.skill.create({
    data: { name: 'Bow Hunting' },
  })

  const hacking = await db.skill.create({
    data: { name: 'Computer Hacking' },
  })

  const allSkills = [{ id: nunchuk.id }, { id: bow.id }, { id: hacking.id }]

  console.log('Create Worker')
  const napolean = await db.worker.create({
    data: { name: 'Napolean Dynamite', skills: { connect: allSkills } },
  })

  console.log(napolean)

  const kip = await db.worker.create({
    data: { name: 'Kip', skills: { connect: { id: hacking.id } } },
  })

  console.log(kip)

  const napoleanWithSkills = await db.worker.findFirst({
    where: { name: 'Napolean Dynamite' },
    include: { skills: true },
  })

  console.log(napoleanWithSkills)

  const kipWithSkills = await db.worker.findFirst({
    where: { name: 'Kip' },
    include: { skills: true },
  })

  console.log(kipWithSkills)
}

main()
  .catch((e) => console.error(e))
  .finally(async () => {
    await db.$disconnect()
  })

And the output of yarn rw db seed is:

Seeding your database... [started]
Create Skill
Create Worker
{ id: 1, name: 'Napolean Dynamite' }
{ id: 2, name: 'Kip' }
{
  id: 1,
  name: 'Napolean Dynamite',
  skills: [
    { id: 1, name: 'Nunchuk' },
    { id: 2, name: 'Bow Hunting' },
    { id: 3, name: 'Computer Hacking' }
  ]
}
{ id: 2, name: 'Kip', skills: [ { id: 3, name: 'Computer Hacking' } ] }
Seeding your database... [completed]

Create the Worker and Skills at same time (but be wary on uniquess, dupes, collisions)

/* eslint-disable no-console */
const { PrismaClient } = require('@prisma/client')
const dotenv = require('dotenv')

dotenv.config()
const db = new PrismaClient()

async function main() {
  const nunchuk = { name: 'Nunchuk' }

  const bow = { name: 'Bow Hunting' }

  const hacking = { name: 'Computer Hacking' }

  console.log('Create Worker')
  const napolean = await db.worker.create({
    data: {
      name: 'Napolean Dynamite',
      skills: { create: [nunchuk, bow] },
    },
  })

  console.log(napolean)

  const kip = await db.worker.create({
    data: {
      name: 'Kip',
      skills: { create: [hacking] },
    },
  })

  console.log(kip)

  const napoleanWithSkills = await db.worker.findFirst({
    where: { name: 'Napolean Dynamite' },
    include: { skills: true },
  })

  console.log(napoleanWithSkills)

  const kipWithSkills = await db.worker.findFirst({
    where: { name: 'Kip' },
    include: { skills: true },
  })

  console.log(kipWithSkills)
}

main()
  .catch((e) => console.error(e))
  .finally(async () => {
    await db.$disconnect()
  })

then seeding will:

Seeding your database... [started]
Create Worker
{ id: 1, name: 'Napolean Dynamite' }
{ id: 2, name: 'Kip' }
{
  id: 1,
  name: 'Napolean Dynamite',
  skills: [ { id: 1, name: 'Nunchuk' }, { id: 2, name: 'Bow Hunting' } ]
}
{ id: 2, name: 'Kip', skills: [ { id: 3, name: 'Computer Hacking' } ] }
Seeding your database... [completed]
✨  Done in 1.68s.

But, when creating, you need to name sure what you are nesting/creating will be unique.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment