typescript - Prisma uppdatera eller skapa och radera gamla relationer


Jag har ett projekt som består av Posts och varje inlägg kan ha en samling av Tags. Jag försöker möjliggöra en redigeringsfunktion som tillåter att taggar för inlägg uppdateras/läggs till/tas bort. För närvarande gör min fråga en upsert av dessa taggar, men jag upplever vissa problem som orsakas av raderaspekten. Varje gång nya taggar skapas, eftersom de inte har någon ID vid det tillfället, tas de bort omedelbart.

await Prisma.post.update({
            where: {
                id: postId,
            },
            data: {
                title,
                content,
                updatedAt: new Date(),
                tags: {
                    // Upsert tags, remove tags that are not in the request
                    upsert: tags.map((tag) => ({
                        where: {
                            id: tag.id ? tag.id : "0",
                        },
                        create: {
                            name: tag.name,
                            color: tag.color,
                            creator: {
                                connect: {
                                    id: session.user.id,
                                },
                            },
                        },
                        update: {
                            name: tag.name,
                            color: tag.color,
                        },
                    })),
                    deleteMany: {
                        id: {
                            notIn: tags.map((tag) => tag.id ?? "0"),
                        },
                    },
                },
            },
            include: {
                tags: true,
            },
        });

Jag har försökt olika lösningar såsom att använda namnet eller andra egenskaper (t.ex. namn OCH färg). Ingen av dessa verkar lösa problemet, eftersom de slutar med att duplicera taggar och orsaka liknande fel.

Här är schemat jag använder i mina Post- och Tag-modeller.

Post
model Post {
    id        String    @id @default(uuid())
    createdAt DateTime  @default(now())
    updatedAt DateTime  @updatedAt
    deletedAt DateTime?

    title    String
    content  String
    authorId String
    author   User      @relation(fields: [authorId], references: [id])
    comments Comment[]
    tags     Tag[]
}
Tag
model Tag {
    id        String   @id @default(uuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt

    name      String
    color     String
    creatorId String
    creator   User   @relation(fields: [creatorId], references: [id])
    posts     Post[]
}

Om någon kunde visa mig rätt riktning för hur man hanterar en situation som denna, skulle jag vara mycket tacksam.

Svar #1

Du bör klippa ut dina steg i en transaktion för att ta bort taggar som inte finns i frågan innan du infogar de nya. Sedan kan du skapa och uppdatera dina data och returnera ditt inlägg

Med interaktiva transaktioner

I din schema.prisma bör du aktivera interactiveTransactions, för detta:

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["interactiveTransactions"]
}

Skär sedan ut dina steg i en transaktion

// Remove <Post> if you aren't in typescript
await prisma.$transaction<Post>(async (trx) => {
  const existingTags = tags.filter(({ id }) => id);
  const newTags = tags.filter(({ id }) => !id);

  await trx.tag.deleteMany({
    where: {
      id: {
        notIn: existingTags.map(({ id }) => id),
      },
    },
  });
  // Update the existing tags
  await Promise.all(
    tags.map((tag) =>
      trx.tag.update({
        where: {
          id: tag.id,
        },
        data: {
          color: tag.color,
          name: tag.name,
        },
      })
    )
  );
  await trx.tag.createMany({
    data: newTags.map((tag) => ({
      ...tag,
      creator: {
        connect: {
          id: session.user.id,
        },
      },
    })),
  });
  return trx.post.update({
    where: {
      id: postId,
    },
    data: {
      title,
      content,
      updatedAt: new Date(),
    },
    include: {
      tags: true,
    },
  });
});

Relaterade artiklar