You should cut out your steps in a transaction to delete the tags not in the query before inserting the new ones. Then you can create and update your data and return your post

With interactiveTransactions

In your schema.prisma you should enable interactiveTransactions, for this:

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

Then cut out your steps in a transaction

// 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,
    },
  });
});
Answer from Pompedup on Stack Overflow
🌐
Prisma
v1.prisma.io › docs › 1.34 › prisma-client › basic-data-access › writing-data-TYPESCRIPT-rsc7
Prisma 1.34 - Writing Data (TypeScript) with TypeScript
upsert: Updates a Post record that is connected to a User record via the author field or creates a new Post record and connects it via the author field to the User record.
🌐
SabinTheDev
sabinadams.hashnode.dev › basic-crud-operations-in-prisma
Prisma and TypeScript CRUD Basics - Sabin Adams
June 21, 2024 - Easy stuff! It's so nice how Prisma allows us to compose queries and operations in a way that is so intuitive. Let's move on to the last update function. Upsert is a special update. I wasn't sure whether to stick this one in the Create section or here with the Updates.
Discussions

using upsert properly.
There was an error while loading. Please reload this page More on github.com
🌐 github.com
1
1
July 30, 2023
database - How to use upsert with Prisma? - Stack Overflow
I'm trying to either update or create a record in my Profile table. I'm using Prisma to define the schema and it looks like this: model Profile { id String @id @default(cuid()) username ... More on stackoverflow.com
🌐 stackoverflow.com
mysql - Create or update one to many relationship in Prisma - Stack Overflow
I imagine the object you're passing ... the TypeScript types, Prisma will tell you exactly what options are available. If you're trying to add new features, and update specific ones, you would need to specify how Prisma can find an old feature (if it exists) to update that one. Upsert won't work ... More on stackoverflow.com
🌐 stackoverflow.com
Unsafe return of any typed value, using prisma upsert
© 2026 Hedgehog Software, LLC · TwitterGitHubDiscord · System · Light · CommunitiesDocsAboutTermsPrivacy · Unsafe return of any typed value, using prisma upsert - Theo's Typesafe Cult · Theo's Typesafe Cult•4y ago• · 18 replies · Christian Lind · Unsafe return of any typed value, ... More on answeroverflow.com
🌐 answeroverflow.com
January 29, 2023
🌐
Prisma
prisma.io › home › type safety overview › type safety overview › type safety overview
Type safety | Prisma Documentation
The UncheckedInput types are a special set of generated types that allow you to perform some operations that Prisma Client considers "unsafe", like directly writing relation scalar fields. You can choose either the "safe" Input types or the "unsafe" UncheckedInput type when doing operations like create, update, or upsert.
🌐
Paigeniedringhaus
paigeniedringhaus.com › blog › tips-and-tricks-for-using-the-prisma-orm
Tips and Tricks for Using the Prisma ORM | Paige Niedringhaus
/** * Insert or update the event ... like we are in our project, just define the JSON field value as an object and then simply pass it in as one of the values in the Prisma upsert() function....
🌐
xjavascript
xjavascript.com › blog › how-to-upsert-many-fields-in-prisma-orm
How to Upsert Multiple Fields in Prisma ORM with a Single Query: A Complete Guide — xjavascript.com
This guide will walk you through everything you need to know to upsert multiple fields in Prisma, from basic syntax to advanced edge cases. By the end, you’ll be able to confidently use Prisma’s upsert to handle complex data operations with minimal code.
🌐
Prisma
prisma.io › home › crud › crud › crud › crud
CRUD (Reference) | Prisma Documentation
const upsertUser = await prisma.user.upsert({ where: { email: "viola@prisma.io" }, update: { name: "Viola the Magnificent" }, create: { email: "viola@prisma.io", name: "Viola the Magnificent" }, });
Find elsewhere
🌐
NestJS
docs.nestjs.com › recipes › prisma
Prisma | NestJS - A progressive Node.js framework
Prisma is an open-source ORM for Node.js and TypeScript. It is used as an alternative to writing plain SQL, or using another database access tool such as SQL query builders (like knex.js) or ORMs (like TypeORM and Sequelize).
Top answer
1 of 2
14

I'm providing my solution based on the clarifications you provided in the comments. First I would make the following changes to your Schema.

Changing the schema

model A_User {
  id        Int          @id
  username  String
  age       Int
  bio       String       @db.VarChar(1000)
  createdOn DateTime     @default(now())
  features  A_Features[]
}

model A_Features {
  id          Int      @id @default(autoincrement())
  description String   @unique
  users       A_User[]
}

Notably, the relationship between A_User and A_Features is now many-to-many. So a single A_Features record can be connected to many A_User records (as well as the opposite).

Additionally, A_Features.description is now unique, so it's possible to uniquely search for a certain feature using just it's description.

You can read the Prisma Guide on Relations to learn more about many-to-many relations.

Writing the update query

Again, based on the clarification you provided in the comments, the update operation will do the following:

  • Overwrite existing features in a A_User record. So any previous features will be disconnected and replaced with the newly provided ones. Note that the previous features will not be deleted from A_Features table, but they will simply be disconnected from the A_User.features relation.

  • Create the newly provided features that do not yet exist in the A_Features table, and Connect the provided features that already exist in the A_Features table.

You can perform this operation using two separate update queries. The first update will Disconnect all previously connected features for the provided A_User. The second query will Connect or Create the newly provided features in the A_Features table. Finally, you can use the transactions API to ensure that both operations happen in order and together. The transactions API will ensure that if there is an error in any one of the two updates, then both will fail and be rolled back by the database.


//inside async function
const disconnectPreviouslyConnectedFeatures =  prisma.a_User.update({
    where: {id: 1},
    data: {
        features: {
            set: []  // disconnecting all previous features
        }
    }
})

const connectOrCreateNewFeatures =  prisma.a_User.update({
    where: {id: 1},
    data: {
        features: {
            // connect or create the new features
            connectOrCreate: [
                {
                    where: {
                        description: "'first feature'"
                    }, create: {
                        description: "'first feature'"
                    }
                },
                {
                    where: {
                        description: "second feature"
                    }, create: {
                        description: "second feature"
                    }
                }
            ]
        }
    }
})

// transaction to ensure either BOTH operations happen or NONE of them happen.
await prisma.$transaction([disconnectPreviouslyConnectedFeatures, connectOrCreateNewFeatures ])

If you want a better idea of how connect, disconnect and connectOrCreate works, read the Nested Writes section of the Prisma Relation queries article in the docs.

2 of 2
2

The TypeScript definitions of prisma.a_User.update can tell you exactly what options it takes. That will tell you why the 'features' does not exist in type error is occurring. I imagine the object you're passing to data takes a different set of options than you are specifying; if you can inspect the TypeScript types, Prisma will tell you exactly what options are available.

If you're trying to add new features, and update specific ones, you would need to specify how Prisma can find an old feature (if it exists) to update that one. Upsert won't work in the way that you're currently using it; you need to provide some kind of identifier to the upsert call in order to figure out if the feature you're adding already exists.

https://www.prisma.io/docs/reference/api-reference/prisma-client-reference/#upsert

You need at least create (what data to pass if the feature does NOT exist), update (what data to pass if the feature DOES exist), and where (how Prisma can find the feature that you want to update or create.)

You also need to call upsert multiple times; one for each feature you're looking to update or create. You can batch the calls together with Promise.all in that case.

const upsertFeature1Promise = prisma.a_User.update({
  data: {
    // upsert call goes here, with "create", "update", and "where"
  }
});
const upsertFeature2Promise = prisma.a_User.update({
  data: {
    // upsert call goes here, with "create", "update", and "where"
  }
});
const [results1, results2] = await Promise.all([
  upsertFeaturePromise1,
  upsertFeaturePromise2
]);
🌐
GitHub
github.com › prisma › prisma › labels › topic: upsert
Issues · prisma/prisma
Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, MongoDB and CockroachDB - Issues · prisma/prisma
Author   prisma
🌐
Answer Overflow
answeroverflow.com › m › 1069229816378822826
Unsafe return of any typed value, using prisma upsert
January 29, 2023 - setTheoryModule: protectedProcedure .input(z.object({ moduleName: z.string(), state: z.boolean() })) .mutation(async ({ input, ctx }) => { const user = ctx.session.user.id; const { moduleName, state } = input; const setTheoryModule = await ctx.prisma.theoryProgress.upsert({ where: { userId: user, moduleName: moduleName, }, create: { userId: user, moduleName: moduleName, state: state, }, update: { state: state, }, }); return setTheoryModule; }), Its saying that "Unsafe assignment of an
🌐
DEV Community
dev.to › dailydevtips1 › how-to-perform-non-updating-upserts-in-prisma-4e3a
How to perform non updating upserts in Prisma - DEV Community
October 28, 2021 - const playlist = await prisma.playlist.upsert({ where: { uri: uri, }, update: {}, create: playlistItem, });
🌐
Angularfix
angularfix.com › 2022 › 03 › how-is-upsertmany-implemented-in-prisma.html
How is .upsertMany() implemented in Prisma ORM? ~ angularfix
March 17, 2022 - const collection = await prisma.$transaction( userData.map(cur => prisma.cur.upsert({ where: { id: cur.id }, update: {}, create: { id: cur.id }, }) ) )
🌐
GitHub
github.com › prisma › prisma › issues › 5233
`upsert()` `where` is defined as `number | undefined` but does not allow `undefined` to not select anything · Issue #5233 · prisma/prisma
January 21, 2021 - Hi, the where object shows a hint that it is of type number | undefined, but I am unable to use undefined. I must specify where: {unique_id: 0} to get it working or am I missing something?
Author   prisma
🌐
GitHub
github.com › prisma › prisma › discussions › 16882
Using upsert · prisma/prisma · Discussion #16882
Is there any way for me use upsert this way, or should I just use create and update. prisma.server.upsert({ where: { id: input.id }, update: input, create: { ...input, owner: { connect: { id: ctx.session.user.id } } } })
Author   prisma
🌐
Prisma
prisma.io › home › seeding › seeding › seeding › seeding
Seeding | Prisma Documentation
import "dotenv/config"; import { Pool } from "pg"; import { PrismaPg } from "@prisma/adapter-pg"; import { PrismaClient } from "../prisma/generated/client"; const connectionString = `${process.env.DATABASE_URL}`; const pool = new Pool({ connectionString }); const adapter = new PrismaPg(pool); const prisma = new PrismaClient({ adapter }); async function main() { const alice = await prisma.user.upsert({ where: { email: "alice@prisma.io" }, update: {}, create: { email: "alice@prisma.io", name: "Alice", posts: { create: { title: "Check out Prisma with Next.js", content: "https://www.prisma.io/next