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
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.
Great insights as always, thank you
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
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)Great thank you!
would cascading delete be a possible feature that can come to Convex?
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