I Want to Do
I have a type like so:
type Membership {
user
club
token
}
with the following schema:
user: uid @reverse .
club: uid @reverse .
token: string .
The user and club types are omitted for brevity.
I’d like to make sure that I cannot duplicate memberships.
The problem is I cannot add an @upsert
to uid types because it does not allow me to create indexes on them.
Since I can’t create an upsert directive, I am unable to guard against concurrent membership creations and I end up with duplicate memberships if the user and the club are exactly the same.
What I Did
Concurrently ran 5 of the following upserts with userEmail and clubName being the same but token is different every time:
upsert {
query addMembership($userEmail: string, $clubName: string) {
user as users(func: eq(email, $userEmail)) {
uid
membership as memberships: ~user @cascade {
uid
club @filter(eq(clubName, $clubName)) {
uid
}
}
}
club as clubs(func: eq(clubName, $clubName))
}
mutation @if(eq(len(membership), 0)) {
_:m <dgraph.type> "Membership" .
_:m <user> uid(user) .
_:m <proxy> uid(proxy) .
_:m <token> "<some random token>" .
}
}
Note that if I have an @upsert
on the token and the token happens to be the same concurrently, then I end up with concurrent Abort errors and all is good. However, I cannot guarantee that the token is going to be the same so I need to make the upsert aborting on the edge itself which does not work.
I can potentially add directly on the Membership type and ensure that it has an @upsert
directive (which it does)…But that feels like defeating the whole purpose of a graph based database by duplicating fields across different nodes.