Querying an arbitrary UID always returns a result

This is probably my favorite thing that when really understood goes a long way in understanding how Dgraph actually works.

Fun fact, a uid never exists and always exists at the same time in Dgraph

As you discovered above it always exists, but in the database it never exists. Proof of this concept is that if you do this mutation assuming you have no data on uid 0x2a (pick any other non-used uid for this):

set {
  uid("0x2a") <dgraph.type> "example" .
  uid("0x2a") <name> "Foo" .
  uid("0x2a") <description> "The answer is found at uid 42" .
}

And then you turn right around and do this mutation:

delete {
  uid("0x2a") <dgraph.type> * .
  uid("0x2a") <name> * .
  uid("0x2a") <description> * .
}

You delete the predicates, but you did not delete the uid itself, so you might reason to suspect that you need to drop all data or do something to delete the pointer subject of 0x2a But the truth is that if you were to export your data, you would find that 0x2a is nowhere to be found in your data.

So if you didn’t delete it, then where did it go? — It never existed by itself.


Dgraph stores data in triples. There is only ever one uid stored in the database by itself, maxuid, and that is just used as a reference of where to generate new uids starting from that stored uid and then update it.

So understanding this concept, how does a query using the uid actually work such as you exampled above? First, it gets the universe by your specific uids. And this get universe is deceiving, because if uids don’t really exist in the db besides as subjects in triplets, then what is it getting since it is not getting any predicates. And this is the explanation: The root uid() function does not actually perform any get operation. All it does it start with a list of uids to use when doing the following steps of filtering and predicate/edge selection.

So if you don’t do any filtering or edge selection, and only request the uid in response, then the uid will always be returned. Because no actual get operation was performed to the datastore.

While this workaround works,

it is not efficient. The reason being is that it is getting the universe of the dgraph.type and then filtering. To make it more efficient, swtich the filter and root function like:

q(func: uid(0x12345)) @filter(has(dgraph.type)) { 
    uid
    name
    email
}
2 Likes