Uids from merged INSERT / Update mutation

Hi. Disclaimer: I’m working with NodeJs and the oficial javascript client.

I found it very error prone the way you get back the uids from a mutation.

Its a very common scenario to run a mutation ordered by the client and have to return the generated uids, so if the user wants to edit something right after he inserted it, the client interface can handle the task.

But, when I do a mutation it can contain a bunch of updates and inserts mixed as far the way dgraph goes, witch is GREAT in my opinion. The problem is that now I have to map the uids from the result, back to the client.

Picture this data send to server as an exemple:

d = {
   user: "test",
   uid: "0x1",
   emails: [
      {
         email: 'test@mail.com'
      }
   ]
}

In this simple case, if I send this json to a mutation I’ll be doing an update in user, as I’m providing a known UID, and inserting a new “email” along an edge “emails” conecting both.

When I get back the uids:

let res = await txn.mutate(upd);
uids = res.getUidsMap();

I got an array of “blanks-nn” that I’ll have to parse in order to figure out whoswho. If I’m misunderstanding something or just doing plain wrong, please do tell me, but I think the response of this mutation should be something like:

{
   uid: "0x1",
   emails: [
      {
         uid: 0x2
      }
   ]
}

So I dont have to be guessing the map back and a simple:

_.merge(d, res);

would solve it.

Any thoughts?

You can add an extra Query to this mutation, right after it. This will be returning the data you need.

If you have two different objects (Nodes) then you can create three blocks. One to locate the two UIDs, the other two to filter by type/kind. You can use “has (_email)” and “has (_user)” to filter. But as they have link, you can simply expand the user.

In this case:

{
   "uid": "_:alice",
   "name": "Alice",
   "user": "test",
   "emails": {
     "uid": "_:email",
     "email": "test@mail.com"
   }
}

Then use:

uid = ag.getUidsMap().get(alice);

and then expand Alice. Using “expand (_all_)” or whatever format you want in the new Query.

1 Like

Well, I cant say that I’m ok with the double query approach, it doesnt seems right to me do another query just to fetch an info thats already served, only not in the best format.

Anyway, you gave me a good point: I changed my posting processor to check whenever there is a uid missing on a node, and to auto fill it with like that:

data['uid'] = "_:" + type + '-' + (num || 0);

this way, after the mutation I can do a “mergeUIds” like this:

    /**
     * Inclui o(s) uid(s) do resultado da operação em data
     * @param data
     * @param uids
     * @private
     */
    __mergeUids(data, uids, key, num){

        // Seta Uid
        if (_.isPlainObject(data)){
            let uid = uids.get(`${key}-${num}`);
            if (uid){
                data['uid'] = uid;
            }

            // Scan por sub
            _.forEach(data, (obj, key) => {
                if (typeof obj === "object"){
                    this.__mergeUids(obj, uids, key, 0);
                }
            })

        } else if (Array.isArray(data)){
            data.forEach((v, i) => {
                if (_.isPlainObject(v)){
                    this.__mergeUids(v, uids, key, i);
                }
            });
        }
    }

Working real good =]

Thanks!!

1 Like

Cara, quando vi “Inclui o(s) uid(s) do resultado da operação em data” eu fiquei confuso kkkkkkk achei que estava ficando maluco ou com poderes de ler inglês como se tivesse escrito em português. Depois lembrei que você é brasileiro kkkkkkk

1 Like