I would like to know how to handle
I would like to know how to handle cascade delete in convex db
13 Replies
Welcome @edmarfo ! There's a delete method on the
db
object inside of a mutation which you can use to delete an object by ID.
https://docs.convex.dev/api/interfaces/server.DatabaseWriter#delete
Is this what you're looking for?Interface: DatabaseWriter | Convex Developer Hub
server.DatabaseWriter
you can also manually delete them from the dashboard - if that's what you're looking for
https://docs.convex.dev/using/dashboard#deleting-documents
Dashboard | Convex Developer Hub
Dashboard Projects View
delete on one-to-many relation table
i would like to know what happens when you delete a document whose id is referenced by other documents. What would be the best practice to handle such situtations
oh - thanks for clarifying. I believe what you're referring to is Referential Integrity - https://en.wikipedia.org/wiki/Referential_integrity. Convex doesn't guarantee referential integrity - IE, you are allowed to have dangling references.
If you call
db.get(id)
on an ID that isn't found, it'll return null. (https://docs.convex.dev/api/interfaces/server.DatabaseReader#get)Interface: DatabaseReader | Convex Developer Hub
server.DatabaseReader
We did actually prototype with referential integrity in earlier versions of the product, but chose to start without it because of the additional complexity it adds (blocking deletes that are referenced elsewhere).
Would be really interested in hearing any input you have as the product is always evolving.
I see. Thanks for clarifying that up for me.
My pleasure!
Is there any updates on the cascades delete part? Came into similar problem recently, it's okay for me to handle it on my side but it would be great if this is something to be handled officially just like most relational database does.
i think Indy might have covered this already but yeah it's not currently supported. we've had designs for this in the past, as well as a separation between strong and weak refs (strong references meaning we ensure the other row always exists) but have kept it simple for now. there were also some usability concerns around deletes cascading further than intended
something we might consider adding again in the future! in the meantime you'll have to do this manually unfortunately
what woud be the proper way to do this? Call scheduled actions that delete the orphan references from the delete mutation?
For most use-cases where there isn't particularly deep chaining it's likely possible just to write an application-level cleanup function that transactionally deletes a document and any dependent documents, e.g., if one was building a todo app that has projects and tasks it would look up a project id, delete the project, then fetch all tasks that match the project id, and delete them too, etc. This will work on the order of low thousands of dependent tasks but if you had tens of thousands of tasks then those would have to be deleted incrementally in a second transaction.
If you have a scenario like a chat app where there's a channel and potentially many many thousands of chat messages in it, I would do it in a multi-phase way:
1. Have a field on the channel document saying
deleting
or whatever. If a channel has deleting=true
then it shouldn't show up in the app.
2. Have a mutation that deletes a batch of chat messages for the corresponding channel and then reschedules itself if there are still messages left.
3. Once that mutation deletes the last message then have it go delete the channel.
If you can do this with mutations instead of actions you get the guarantee that mutations will be retried.
I do a degenerate version of this in rap-genie:
https://github.com/JamesCowling/rap-genie/blob/a3e58e4327e7a5a526bdbbb25179063f9c98ec85/convex/songs.ts#L209GitHub
rap-genie/convex/songs.ts at a3e58e4327e7a5a526bdbbb25179063f9c98ec...
Rap Genie is a semantic search engine for rap verses, built on Convex vector search. - JamesCowling/rap-genie
that makes a whole lot of sense, thanks!
maybe the native support of deleting files associated with
Id<'_storage'>
would be really helpful