Intersect version of uid(…)

I want to get the intersection of a set of uid vars. This is similar to Get output of uid(a,b,...) as intersection not union, but I did not want to reopen that lengthy discussion.

I can turn uid(…), which does the union of its vars, into an intersection with a @filter as follows:

pred1 as var(func: has(<dgraph.graphql.schema>))
pred2 as var(func: has(<dgraph.graphql.xid>))
pred3 as var(func: has(<dgraph.type>))

result (func: uid(pred1,pred2,pred3)) @filter(has(<dgraph.graphql.schema>) AND has(<dgraph.graphql.xid>) AND has(<dgraph.type>)) {
  uid
  <dgraph.graphql.schema>
  <dgraph.graphql.xid>
  <dgraph.type>
}

The uid vars pred1, pred2 and pred3 provide the set of uids already. Applying a @filter and repeating the has operations seems redundant and might not be as performant in its implementation as a uid_intersect(pred1,pred2,pred3) might be:

pred1 as var(func: has(<dgraph.graphql.schema>))
pred2 as var(func: has(<dgraph.graphql.xid>))
pred3 as var(func: has(<dgraph.type>))

result (func: uid_intersect(pred1,pred2,pred3)) {
  uid
  <dgraph.graphql.schema>
  <dgraph.graphql.xid>
  <dgraph.type>
}

And uid_intersect(…) makes this query much more handy and readable. Imagine more vars here.

Any thoughts on that?

Have you tried cascade? I think (from what I got in your question) that it might work for you.

pred1 as var(func: has(<dgraph.graphql.schema>))
pred2 as var(func: has(<dgraph.graphql.xid>))
pred3 as var(func: has(<dgraph.type>))

result (func: uid(pred1,pred2,pred3)) @cascade {
  uid
  <dgraph.graphql.schema>
  <dgraph.graphql.xid>
  <dgraph.type>
}

I have a use case for this:

I want to do filtering at different levels. For instance I need to answer questions like, “Show me contacts (that have an address that have cities that are in X, Y, Z) and (has events that are in the seven days OR has tasks that have occurrences that are not completed and due in the next seven days.)” In order to fulfill similar request, I have to run the filtering logic at a higher level in my UI and get all of the UIDS that fulfill the separate parts and then do the conjunction logic and then pass these UIDS to the filter where I actually get the full graph to use with pagination. Right now my UI has to do much of this logic and it would be nice to unload at least the last part to the database layer.

The cascade is getting better, especially with parameterized cascade coming soon to the main releases. But the cascade cannot support nested logic like OR and only covers some AND logic.

Yes, @cascade would work for that example, but not for this:

pred1 as var(func: has(<dgraph.graphql.schema>))
pred2 as var(func: has(<dgraph.graphql.xid>))
pred3 as var(func: has(<dgraph.type>))

result (func: uid(pred1,pred2,pred3)) @cascade {
  uid
}

And I need the intersection no matter what is in the body of result.

1 Like

@MichelDizso do you agree that uid_intersect would be a concise addition to the GraphQL± language?

Sorry for the late reply. You have marked me with the wrong nick.

Well, I think the cascade work well. I can’t see how that would work well different from the cascade. See, if the query doesn’t have anything to compare, it would have any arbitrary comparison and maybe it wouldn’t be expected result as it would be with explicitly “params”.

Let’s take your last query into account. What would be the rules? The node with more predicates? So, all the other nodes would be parameterized by it? Or it would infer all possible nodes and gather all possible predicates? but in that case, maybe you would never have any result.

For me, the cascade is the best solution for now.

Cheers.