How to create unique field in Convex
How do I restrict the
name
to be unique meaning, two document can't have same name?
7 Replies
I don’t think this is possible but when creating the mutation u can do something like query the field with an index of the name and of the name already exists throw an error or do something with that but if the name dosent exist continue with the function would this work? @erquhart i used it once
this seems like a very important feature.
over the years using apis, a pattern I've seen that makes an API a lot easier to use is the idea that every object has an internal unique identifier that the API's own system creates and also another unique identifier that the API user can set
this is especially useful for integrating between systems that already exist before you start using the API
This is how you do it. It's ~2 extra lines of code wherever you create the document or modify its 'name' field
And if you are creating or modifying the name in many places, you can put the constraint in a row-level-security rule or something similar https://www.npmjs.com/package/convex-helpers, and then it will be enforced on every db.insert/db.patch/db.replace
To recap:
- Declare an index using the
name
field
- Whenever creating or modifying documents, check that there isn't an existing document with the same name
- If this needs to be done in multiple places, wrap the logic in a JS/TypeScript function
- If you need to do this for many different documents and fields, check out convex-helpers
for utilities that helpAnother approach, which I've taken, is pulling db operations out of my convex functions and creating "db functions" - they're just functions that I pass the context object to. Give them useful names, handle authz, enforce uniqueness, validation, etc in the db function and you don't have to worry about any of that at the call site. I'm still not certain how well this will age compared to middleware, but it's similar to how things are structured with frontend libs like react query, where you have dedicated and often reused functions for fetching.
I just finished a pretty big overhaul in this direction, I have more details if it's helpful for anyone.
@ian and @erquhart I'm pretty sure you guys are connecting, right? Ian is thinking through something similar for middleware vs. a kind of macro layer gluing together these functions
Yeah we've definitely connected on middleware, he also shared his in progress work for me to try out. The challenge is I personally prefer keeping things highly declarative (perhaps to a fault), so I'm more likely to pass the context around everywhere like a football than to use middleware. I haven't heard much about the macro layer concept, interested to hear more.