I’m struggling a bit with a query I’m trying to write. The idea behind it seems very simple to me, yet after reading the docs and playing around with Dgraph for a bit, I’m still not able to accomplish the following:
How would I find nodes that have a certain relation to all of a list of uids?
The only thing I could come up with is
query {
q(func: has(name)) @filter(uid_in(~relation, "0x2744") AND uid_in(~relation, "0x2741")) {
uid
name
}
}
But I want something more dynamic where I can pass a list of uids as variable, instead of hardcoding a query like that.
So with my example data, I would expect the query
called with the uids of [one, two, three] to return ten
called with the uids of [one, two] to return ten
called with the uids of [two] to return ten and eleven
I hope my explanation makes sense.
Can I write such a query with Dgraph?
In the last example, as both Ten and Eleven are related to Node “Two”. I needed to set a parameter to make sure it has only a single relationship and no more than one. Using eq (count (~ relation), 1). It’s kind of a trick, but avoids returning unwanted sets. You can use @filter(gt(count(~relation), 1) (Greater than) if you need tho.
Thanks for your thorough response @MichelDiz!
Seems like I failed to explain what I need
First, I’m trying to query by uid, not name. Could those simply be swapped in your queries?
Your queries also make assumptions about the data if I’m not mistaken.
Would it be possbile to build one universal query that does “find nodes that have a certain relation to all nodesof a list of uids”, making no assumptions about the available data (e.g. any node could have any amount of relations to any node, and you know nothing about the data except the schema)?
Are you sure this would work?
In my testing this doesn’t return anything.
I think that’s because it searches for a relation that is pointing to two nodes, which isn’t possible. There can’t be a single relation that matches @filter(uid(0x2744) AND uid(0x2741) )
I think you can create this logic with use of query blocks like this:
{
Q1 as var(func: has(name)) @cascade {
uid
name
~relation @filter(eq(name,"One"))
}
Q2 as var(func: has(name)) @cascade {
uid
name
~relation @filter(eq(name,"Two"))
}
Q3 as var(func: has(name)) @cascade {
uid
name
~relation @filter(eq(name,"Three"))
}
result(func: has(name)) @filter(uid(Q1) AND uid(Q2) AND uid(Q3)) {
uid
name
}
}
You could programmatically create this query for any number of arguments without any need for hardcoding, and since dgraph processes query blocks in parallel, it should return results quite fast even for bigger queries; however I wonder, if this can be done in an more elegant/efficient way.