Search code examples
databaseblogsprisma

How to use connectOrCreate with many to many in prisma


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 })), 
      },
    },
  },
});

Solution

  • 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 },
                };
            }),
        },
      },
    });