prisma / prisma1

💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated]
https://v1.prisma.io/docs/
Apache License 2.0
16.54k stars 862 forks source link

Mutation CreateOrConnect #3724

Closed muhajirdev closed 2 years ago

muhajirdev commented 5 years ago

Hey guys, suppose I have data model like this.

type User {
  id: ID! @unique
  authorId: String! @unique
  name: String!
  messages: [Message!]!
}

type Message {
  id: ID! @unique
  content: String
  author: User!
}

Suppose I have this message data in this form

// example message data
 {
  authorId: 'some-id",
  content: "some content"
}

I want to record that message in database. And create new user with that authorId, if it doesn’t exist yet.

async function recordMessage(message) {
  const userExists = await prisma.$exists.user({
      authorId: data.authorId
    });

  if (!userExists) {
    await prisma.createAuthor({
      authorId: data.authorId
    })
  }

  prisma.createMessage({
    content: data.content,
    author: {
      connect: {
        authorId: data.authorId
      }
    }
  });
}

Sometime one message and another message have same authorId. That’s why I check userExist first. But, when I run recordMessage(message), alot of times. Sometime it result in race condition, it says user doesn’t exist yet. But when we’re creating new author, I got Unique constraint Error. Which means there’s already user with that authorId right?

How do you guys handle this situation?

Is there any plan in the future for something like this:

Similar to upsert pattern

prisma.createMessage({
    content: data.content,
    author: {
      createOrConnect: {
        where: {
           authorId: data.authorId
         }
        create: {
            authorId: data.authorId
            name: "somename"
        }
        connect: {
           authorId: data.authorId
        }
      }
    }
  });
}
prisma.createOrConnectAuthor({ 
  where: { 
    authorId: "some-id"
  },
  create: {
    authorId: "some-id"
  },
  connect: {
    authorId: "some-id"
  }
})

or

prisma.findOrCreateAuthor({
     authorId: "some-id"
})

Some ORM have this feature, like http://docs.sequelizejs.com/manual/tutorial/models-usage.html#-findorcreate-search-for-a-specific-element-or-create-it-if-not-available .

Well, I conclude the paint point here is that when creating new data that depends on another node, but you're not sure that node already exist or not.

Thanks

mavilein commented 5 years ago

@muhajirframe : I would to the following here:

  1. Use upsertUser to create a user if it does not exist yet. I would leave the update params for this mutation empty as you do not want to update something.
  2. Just call createMessage as you did before.
muhajirdev commented 5 years ago

Hey @mavilein . Thanks for the answer.

I tried that way, it does works! thanks.

Wondering if the nested mutation could work that way too?

mavilein commented 5 years ago

@muhajirframe : Yes. Your idea for the nested createOrConnect is really neat! Thanks for proposing this 🙏