Prisma1: [Mongo] Cascading deletes

Created on 3 Jan 2019  路  21Comments  路  Source: prisma/prisma1

Cascading deletes is not implemented for the Mongo connector.

A validation should be added to the deploy step to make sure that it is not declared on the data model.

Note: Embedded types by their nature already have a cascading delete effect; deleting a top level type will of course also delete all its embedded types.

kindiscussion statuon-hold areconnectomongo

Most helpful comment

This should definitely be in the docs

All 21 comments

This should be in the docs, i just wanted to create an issue for.

https://github.com/domekol/prisma-mongodb-cascade-relation-bug

This should definitely be in the docs

@do4gr So will this be eventually implemented or is there a reason why?

Our implementation of Cascading Deletes in the SQL connectors relies on transactional guarantees across tables.

Mongo only started supporting cross-document transactions with 4.0. We are at the moment testing at what performance penalty enabling transactions on Mongo comes since this is a very new concept for them.

For what release will this be fixed?

Our prototype that implemented cascading deletes using transactions showed transaction errors (deadlocks etc. ) under heavy concurrency. We therefore cannot implement this feature at the moment.

Until we can we will therefore add an error during deployment to avoid confusion.

Reopening this issue as cascading deletes is not yet implemented for the Mongo connector. However, since we're not tackling this any time soon (see @do4gr's last comment), we're applying the on-hold label for now.

are we talking weeks, months or years?
Do you propose a specific workaround?

I think this will probably take a couple of months until we can focus on this.

any updates regarding this issue, since I am making production ready app so any trick or the third party will also be better for me? @do4gr since its July 11

Is there any new news on this?

I believe this to be major. While there is no updates for this.

Until we can we will therefore add an error during deployment to avoid confusion.

What would be the recommended way to "cascade" deletion on a relation?

cheers

followup... https://github.com/prisma/prisma2/issues/267

Can someone point me to an alternative for now ?

currently, I am doing cascading deletes manually @omarragi

@developerk786 could you give us a simple example :)

it's simple it's my mistake i didn't explain much
let say we have this modal:

type User {
  name: String!
  posts: [Post!]!
}

type Post {
  title: String!
  body: String!
}

let's say we have to delete user with id: 1

// manually delete all relational fields
...otherCodes

const userId = param.userId
const posts = await prisma.posts()

posts.forEach(async post => {
  await prisma.deletePost({ id: post.id })
})

// same for other fields lets say comments do the same as above

await prisma.deleteUser({ id: userId })

...restCodes

So if you have a nested relation like I did, it's gonna be a nightmare.

User => (Posts => Photos) + Comments + Favorites + Friends + ...

It will have to remove all of them when we remove a user. Otherwise they will become null and gather dust in the database for no reason.

Here is the similar code we had to put,

const result = await deleteAction({
    where: {
        id: args.id
    }
}, info);

// TODO: use a queue instead of blocking all connection here
// What if the user has 100k logs on a instance? :/
await Promise.all([
    logs && logs.length && (await deleteManyLogs(logs.map(log => ({
        where: {
            id: log.id
        }
    })))),
    content && (await deleteContent({
        where: {
            id: content.id
        }
    })),
    state && (await deleteState({
        where: {
            id: state.id
        }
    })),
    source && (await deleteSource({
        where: {
            id: source.id
        }
    })),
]);

Then we were forced to refactor them a bit because we had to use them many times on many reducer, the code is kind of similar to this,

const deleteSingle = (group, mutation, info) => group && mutation({
  where: {
      id: group.id
  }
}, info);

const groupMapped = group => group.map(single => ({
  where: {
      id: single.id
  }
}));

const deleteMany = (group, mutation) => group && group.length && mutation(groupMapped(group));

// Run them
// we need to use/return this later
const result = await deleteSingle(args, deleteAction, info);
await Promise.all([
  deleteMany(logs, deleteManyLogs),
  deleteSingle(content, deleteContent),
  deleteSingle(state, deleteState),
  deleteSingle(state, deleteSource)
])

Maybe there is a better way to deal with this, who knows!

@developerk786 @entrptaher Yup, this is what I ended up doing too. It's a pain and more prone to errors. Would be nice if cascading deletes just worked as expected.

@entrptaher Your solution is better than mine =D, for now, we can do this but we can rely on prisma2 for future apps

I just released mongoke, it is a docker image that instantly serves your mongodb database via graphql and , contrary to prisma, works with existing databases, this means that you can directly insert and update the data in your database without worrying about corrupting prisma data model. It generates only graphql queries but you can easily attach other graphql services (to handle custom mutations) thanks to apollo federation.
It also has built in authorization using your jwt which means you can expose directly the service to the open world.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wereHamster picture wereHamster  路  37Comments

marktani picture marktani  路  71Comments

marktani picture marktani  路  71Comments

sapkra picture sapkra  路  40Comments

marktani picture marktani  路  41Comments