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

The MongoDB connector should support transactions for nested mutations #3738

Closed nikolasburk closed 2 years ago

nikolasburk commented 5 years ago

Currently, nested mutations with the MongoDB connector are not executed transactionally and therefore might bring your project into an inconsistent state and break the API. See this issue as an example.

do4gr commented 5 years ago

MongoDB itself started supporting multi-document transactions starting with 4.0.

The Prisma Mongo connector is not officially tested against 4.0 yet but we would expect it to just work. Making use of the transactional capabilities that 4.0 offers is something we would need to explicitly add though.

We currently do not think that the implementation is the main hurdle, the biggest task is to get an understanding of the performance implications and potential deadlock issues this brings with it.

The SQL connectors also always run with transactionality enabled by default. It is not yet clear to us whether this should be the case for Mongo as well or whether users would like to configure this (to avoid performance penalties for example.)

If any one has a strong opinion on this or has specific use cases where they want / do not want it we would like to hear from you!

nikolasburk commented 5 years ago

Thanks a lot for the explanation!

I think this is a very important product decision because not supporting transactions would mean that we're accepting projects to be inconsistent which will lead to errors further down the road when using the same project.

Consider the example from this issue where the following datamodel was used:

type User {
  id: ID! @id
  name: String
  companies: [Company!]! @relation(link: INLINE)
}

type Company {
  id: ID! @id
  name: String
  user: User!
}

Note that the user field is required on the Company model.

But because the transaction failed, there was a Company node created that had no User associated with it! This will lead to a GraphQL error when that Company node with the user relation is being retrieved.

allanplima commented 5 years ago

I just tested with my own API using MongoDB 4.0 and it actually worked. I linked my User with Logs into my type User and Log and then created a new user with the object:

{ firstName: "Allan", lastName: "Lima", email: "allanpinheirodelima@gmail.com", emailVerified: false, logs: { create: [{ resource: "prisma", operation: "delete" }] } }

It was created, but it was a small scale test. Everything worked fine. I don't think we should rush things, but it looks pretty solid with MongoDB 4.0. I'll be watching this thread to know your conclusions

edit

I don't know yet how to format code like the comment from nikolasburk

johnsonjo4531 commented 5 years ago

Hey @allanplima, here's how to format multi-line code on Github. Might I also suggest using json or js as the language like so.

```js
<code goes here>
```

Also if your new to markdown in general I recommend reading Github's markdown guide or the Mastering Markdown guide they are both pretty similar so only reading one is fine.

monojack commented 5 years ago

Doesn't work for me with MongoDB 4.0.6.

Im trying this (from the docs)

const newUserWithLinks = await prisma
  .createUser({
    name: "Alice",
    email: "alice@prisma.io",
    password: "IlikeTurtles",
    links: {
      create: [{
        description: "My first link",
        url: "https://www.prisma.io"
      }, {
        description: "My second link",
        url: "https://www.howtographql.com"
      }]
    }, 
  })

the model is:

type Link {
  id: ID! @id
  createdAt: DateTime!
  description: String!
  url: String!
  postedBy: User
  votes: [Vote!]! @relation(link: INLINE)
}

type User {
  id: ID! @id
  name: String!
  email: String! @unique
  password: String!
  links: [Link!]! @relation(link: INLINE)
  votes: [Vote!]! @relation(link: INLINE)
}

type Vote {
  id: ID! @id
  link: Link!
  user: User!
}

and I get the following error:

{
  "result": {
    "data": null,
    "errors": [
      {
        "message": "Variable '$data' expected value of type 'UserCreateInput!' but got: {\"name\":\"Alice\",\"email\":\"alice@prisma.io\",\"password\":\"IlikeTurtles\",\"links\":{\"create\":[{\"description\":\"My first link\",\"url\":\"https://www.prisma.io\"},{\"description\":\"My second link\",\"url\":\"https://www.howtographql.com\"}]}}. Reason: 'links.create[0].createdAt' Expected non-null value, found null. (line 1, column 11):\nmutation ($data: UserCreateInput!) {\n          ^",
        "locations": [
          {
            "line": 1,
            "column": 11
          }
        ]
      },
      {
        "message": "Variable '$data' expected value of type 'UserCreateInput!' but got: {\"name\":\"Alice\",\"email\":\"alice@prisma.io\",\"password\":\"IlikeTurtles\",\"links\":{\"create\":[{\"description\":\"My first link\",\"url\":\"https://www.prisma.io\"},{\"description\":\"My second link\",\"url\":\"https://www.howtographql.com\"}]}}. Reason: 'links.create[0].createdAt' Expected non-null value, found null. (line 1, column 11):\nmutation ($data: UserCreateInput!) {\n          ^",
        "locations": [
          {
            "line": 1,
            "column": 11
          }
        ]
      }
    ],
    "status": 200
  }
}

EDIT:

Didn't pay attention to the reason. I just had to remove the createdAt field from Link and now it works!

byteab commented 5 years ago

so Prisma is not safe and I should implement my own API with mongoose

akhilshastri commented 4 years ago

is there any plan for it ...?