```Invalid `prisma.user.upsert()` invocation: ...
# orm-help
g
Copy code
Invalid `prisma.user.upsert()` invocation:


  Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: RawDatabaseError { code: "unknown", message: "Command failed (WriteConflict): WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.)" } })
What does it mean?
1
n
Hey 👋 This means that if two clients try to perform, for example, an update over the same resource, one of them is going to get a WriteConflict error. Which database are you using? Is this happening intermittently or every time?
g
Hello, @Nurul. Thank you for your response. I am using mongo db. Prisma with nestjs. It is happening intermittently, I couldn't recognize in what exact moment or situation.
n
Can you try performing this operation in a transaction and see if that fixes the issue for you?
g
@Nurul any guide for it please?
n
Here’s an example: The upsert statement is inside a transaction. schema.prisma
Copy code
// This is your Prisma schema file,
// learn more about it in the docs: <https://pris.ly/d/prisma-schema>

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

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model Images {
  imageID         String   @id @default(auto()) @map("_id") @db.ObjectId
  messageID       String?
  userID          String?
  guild           String?
  channelID       String?
  logID           String?
  url             String
  type            String
  interactionType String?
  isVideo         Boolean?
  tags            String[]
  likedBy         Users[]  @relation(fields: [likedByIds], references: [id])
  likedByIds      String[] @db.ObjectId
}

model Users {
  id             String   @id @default(auto()) @map("_id") @db.ObjectId
  premium        Boolean  @default(false)
  tagsSuggested  Int      @default(0)
  baraRequested  Int      @default(0)
  isContribuitor Boolean  @default(false)
  liked          Images[] @relation(fields: [likedImageIds], references: [imageID])
  likedImageIds  String[] @db.ObjectId
}
index.ts
Copy code
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient({
  log: ['query'],
});

async function main() {
  const user = await prisma.$transaction([
    prisma.users.upsert({
      where: {
        id: '62fdeed1fd3ad81be5088625',
      },
      create: {
        baraRequested: 1,
        isContribuitor: true,
      },
      update: {
        baraRequested: 0,
      },
    }),
  ]);

  console.log(user);
}

main()
  .catch((e) => {
    throw e;
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
output:
Copy code
> ts-node index.ts

prisma:query db.Users.aggregate([ { $match: { $expr: { $and: [ { $and: [ { $eq: [ "$_id", ObjectId("62fdeed1fd3ad81be5088625"), ], }, { $or: [ { $ne: [ { $ifNull: [ "$_id", null, ], }, null, ], }, { $eq: [ "$_id", null, ], }, ], }, ], }, ], }, }, }, { $project: { _id: 1, }, }, ])
prisma:query db.Users.insertOne({ premium: false, tagsSuggested: 0, baraRequested: 1, isContribuitor: true, })
prisma:query db.Users.aggregate([ { $match: { $expr: { $and: [ { $and: [ { $eq: [ "$_id", ObjectId("62fdef31bb9d6b0c1dc90110"), ], }, { $or: [ { $ne: [ { $ifNull: [ "$_id", null, ], }, null, ], }, { $eq: [ "$_id", null, ], }, ], }, ], }, ], }, }, }, { $project: { _id: 1, premium: 1, tagsSuggested: 1, baraRequested: 1, isContribuitor: 1, likedImageIds: 1, }, }, ])
[
  {
    id: '62fdef31bb9d6b0c1dc90110',
    premium: false,
    tagsSuggested: 0,
    baraRequested: 1,
    isContribuitor: true,
    likedImageIds: []
  }
]
❤️ 1
g
@Nurul Thank you. Now I don’t face this error, but I don’t know if it is fully fixed, I will let you know if the error occurs again
🙌 1
r
@Nurul I'm running into the same issue on an
updateMany
call. Is this related to this open Prisma issue?
I'm also using NestJS and refactoring my
updateMany
to the
$transaction
doesn't work 😞
Copy code
async updateMany(data: IToken) {
    // updateMany threw following error:
    // WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.
    return await this.prisma.$transaction([
      this.prisma.token.update({
        where: { userId: data.userId },
        data: {
          ...(data.accessToken && { accessToken: data.accessToken }),
          ...(data.refreshToken && { refreshToken: data.refreshToken }),
        },
      }),
    ]);
  }
Here's the error:
Copy code
Error: 
Invalid `this.prisma.token.update()` invocation in
/Users/richardpoelderl/backend/src/auth/auth.repository.ts:22:25

  19 // updateMany threw following error:
  20 // WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.
  21 return await this.prisma.$transaction([
→ 22   this.prisma.token.update(
  Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: RawDatabaseError { code: "unknown", message: "Command failed (WriteConflict): WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.)" } })
g
@Richard Hello, I don’t know what is causing this error on your end, but in my case it was a race condition. Above I said that I didn’t face that error anymore after the usage of transaction, but later it happened again. Then I fixed my code where was a race condition, so this error disappeared
r
Interestingly, I see that my endpoint is called twice very fastly -- maybe this creates an issue on the second endpoint dall as the firt one hasn't finished yet
@Geebrox sorry if I bother you with a NestJS question here, but do you know if there's a way to make a controller wait if another controller execution hasn't finished?
g
@Richard I cannot say that there is only way to do that, it regards on what you are trying to do in the controller. The most easiest way is to use events, IMHO
r
Not sure how to do this frankly.. 😞
(not super experience w/ events based architecture)
I will just run a get query first & compare the values. If they are the same, I will skip the updateMany call
👍 1
Okay, unfortunately That doesn work because the payload is actually hashed & generates tokens so they'll always be different. 😅
I would've expected Prisma's mongo driver to just queue the conflicting updateMany transaction and wait for the other one to finish first. 🤔