How to use connectOrCreate with many to many in prisma
Asked Answered
I

1

5

I want to use Prisma to associate articles with tags, that is: A post has multiple tags and a tag belongs to multiple posts
But the example in Prisma will result in the creation of duplicate tags

Here is my Prisma model

model Article {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  title     String
  summary   String
  link      String   @unique
  archive   String
  content   String
  image     String
  tags      Tag[]
}

model Tag {
  id       Int       @id @default(autoincrement())
  name     String
  articles Article[]
}

This is my code according to the documentation, it causes duplicate tags to appear

await prisma.article.create({
  data: {
    title,
    summary,
    link,
    archive,
    content,
    image,
    tags: {
      create: tags.map((tag) => ({ name: tag })),
    },
  },
});

When I use connectOrCreate, it reports an error in many-to-many mode

await prisma.article.create({
  data: {
    title,
    summary,
    link,
    archive,
    content,
    image,
    tags: {
      connectOrCreate: {
        where: tags.map((tag) => ({ name: tag })),
        create: tags.map((tag) => ({ name: tag })), 
      },
    },
  },
});
Incus answered 21/8, 2021 at 15:7 Comment(1)
what's the reason to use tags.map((tag) => ({ name: tag })) within your code ?Bodgie
M
20

There's two errors in the code.

Tag.name field is not unique

From what I can infer from your domain, two tags should not have the same name. Furthermore, since the name field is not unique, you can't use it by itself to uniquely identify a specific Tag record and so Prisma will complain if you try to pass only the name field in the where condition of connectOrCreate.

The simplest and logical solution to this is to make the name field unique. Here's your updated Tag model

model Tag {
  id       Int       @id @default(autoincrement())
  name     String    @unique  // change
  articles Article[]
}

Incorrect syntax for connectOrCreate

You're passing separate arrays to the where and create fields. Instead, when you want to connect/create multiple records, pass an array of objects to connectOrCreate each with its own where and create field. Here's an example from the Prisma Docs that shows how to use connectOrCreate with multiple records.

This is what your create query should look like:

await prisma.article.create({
  data: {
    title,
    summary,
    link,
    archive,
    content,
    image,
    tags: {
        connectOrCreate: tags.map((tag) => {
            return {
                where: { name: tag },
                create: { name: tag },
            };
        }),
    },
  },
});
Michelson answered 23/8, 2021 at 8:16 Comment(1)
This was a lifesaver. I just want to add, since it might not be obvious by the wording, that the bullet points the author has mentioned work in tandem. It's not either or but utilizing both at the same time. This solved my issue. Thank you!Kyrakyriako

© 2022 - 2025 — McMap. All rights reserved.