erquhart
erquhart•2y ago

Updating the UI for relational batch deletions

Let's say I have an entity that's related to a lot of other entities. If I delete it, I need to paginate through multiple tables to delete the relations first, so I schedule those. Currently I'm setting isDeleted: true on the entity being deleted, which allows me to update the UI right away for the immediate action. In places where related data is being fetched (often paginated), however, I don't see a great way to index/filter for this in queries, so filtering the result based on a list of "deleted" foreign keys is my best bet it seems, which could make paginating odd when large chunks or even entire pages are missing in the filtered result. Just checking to see if I'm missing a better way here. Obviously the golden ticket here is full on relationship support with cascading deletes, but something that could help in the meantime: q.in()/q.nin() support for filters. This way I could provide a list of ids to filter out for the foreign key field.
7 Replies
lee
lee•2y ago
One thing you could consider is adding a wrapper like https://stack.convex.dev/row-level-security that follows the relationship for each document and filters it out if the target object is deleted. But that may be a lot of queries -- you could make it more efficient by fetching all deleted entries with another wrapper and adding that list to the ctx. We're thinking about adding relationship helpers like cascading deletes, but it's difficult to make it efficient regardless of what layer it's in -- you're running into a fundamental perf issue that has to be solved somewhere 😦 . As for q.in, it does seem like a useful helper we could add. For now, you could implement it yourself with q.or(...deletedIds.map(id => q.eq(q.field("relation"), id)))
Row Level Security: Wrappers as "Middleware"
Implementing row-level security on Convex as a library. Wrap access to the database with access checks written in plain old JS / TS.
erquhart
erquhartOP•2y ago
Great insights as always, thank you
Michael Holmes
Michael Holmes•15mo ago
Is it weird I had to use toString() here? .filter(q => q.and(...nameMatchIds.map(id => q.not(q.eq('_id', id.toString()))))) Otherwise the type of nameMatchIds: Id<"organizations">[] results in type error
lee
lee•15mo ago
it looks like you're doing q.eq('_id', id) when you mean to be doing q.eq(q.field('_id'), id) (it also looks unrelated to the above, so i recommend a new support thread)
Michael Holmes
Michael Holmes•15mo ago
Great thank you!
fawwaz
fawwaz•15mo ago
would cascading delete be a possible feature that can come to Convex?
jamwt
jamwt•15mo ago
it's on the list to consider. we actually used to have it back when we had "strong references" because we tracked document relationships. but that had a ton of implementation + performance complexity so we decided not to bake it in to the core of convex it's possible this may be something solved by an ORM layer a little further down the road that "manages" these relationships with libraries build on the convex core layer but nothing imminent coming out, I'm afraid. has to be written manually for now we know some power users have their own little helper libraries ("mini-orms") for these patterns

Did you find this page helpful?