I am using an upsert operation as described in dgraph-js to get or create a new node with a given external id called did and return its uid.
My frontend application makes two requests in parallel, both of which call the upsertProfile function with the same did. The problem is that a new uid is created in both calls, and thus I end with a duplicated entry (two uids pointing to the same did).
If I call again the same function after giving enough time to finish the first two calls, a new uid is not created.
I am not sure this is a bug, as I don’t know if the upsert operation works as expected in parallel operations, and how dgraph handle parallel conflicting mutations
Here is the fuction I use:
async upsertProfile(did: string):Promise<void> {
await this.ready();
const mu = new dgraph.Mutation();
const req = new dgraph.Request();
let query = `profile as var(func: eq(did, "${did}"))`;
req.setQuery(`query{${query}}`);
let nquads = `uid(profile) <did> "${did}" .`;
nquads = nquads.concat(`\nuid(profile) <dgraph.type> "${PROFILE_SCHEMA_NAME}" .`);
mu.setSetNquads(nquads);
req.setMutationsList([mu]);
req.setCommitNow(true);
let result = await this.client.newTxn().doRequest(req);
console.log('[DGRAPH] upsertProfile', {query}, {nquads}, result.getUidsMap().toArray());
}
Here is the log i got:
run in parallel:
[DGRAPH] upsertProfile { query: 'profile as var(func: eq(did, "anonymous:02"))' } {
nquads: 'uid(profile) <did> "anonymous:02" .\nuid(profile) <dgraph.type> "Profile" .'
} [ [ 'uid(profile)', '0x1adc1' ] ]
[DGRAPH] upsertProfile { query: 'profile as var(func: eq(did, "anonymous:02"))' } {
nquads: 'uid(profile) <did> "anonymous:02" .\nuid(profile) <dgraph.type> "Profile" .'
} [ [ 'uid(profile)', '0x1adc2' ] ]
run afterwards:
[DGRAPH] upsertProfile { query: 'profile as var(func: eq(did, "anonymous:02"))' } {
nquads: 'uid(profile) <did> "anonymous:02" .\nuid(profile) <dgraph.type> "Profile" .'
} []