gotjoshua
(gotjoshua)
July 29, 2020, 1:15pm
1
I am in my initial exploration of dgraph and using the basic data from the demo (with some small alterations). The relevant alteration for this question is to the schema:
friendship: [uid] @count @reverse .
I want to build a query that gives incoming, outgoing, and mutual friendships (explicitly bidirectional - meaning that there is an edge set for both directions, not only via @reverse ). So everything except the line for friendships_mutual works in the following query:
{
everyone(func: eq(dgraph.type, "Person")) {
uid
name@* @facets
friendships_outgoing: count(friendship)
friendships_incoming: count(~friendship)
friendships_mutual: ?? HOW_TO ??
friendships: friendship @facets {
uid
name@* @facets
}
}
}
Is there a way to filter and count friendships that are explicitly bidirectional?
MichelDiz
(Michel Diz)
July 29, 2020, 2:53pm
2
Try something like
friendships_mutual: math(incoming = outgoing)
It should return true or false
gotjoshua
(gotjoshua)
July 29, 2020, 3:22pm
3
Thanks @MichelDiz for the quick reply…
i guess you mean incoming == outgoing, right?
What should incoming and outgoing refer to?
I would somehow need to compare uids of the nested friendship triples… but there i have no idea how to isolate them. Intuitively i tried:
is_mutual: math(friendship.uid == uid)
but that doesn’t work.
any more ideas?
MichelDiz
(Michel Diz)
July 29, 2020, 3:27pm
4
You have to use variables
outgoing as friendships_outgoing: count(friendship)
incoming as friendships_incoming: count(~friendship)
update: I’ll come back to your question. There are some points to clarify.
gotjoshua
(gotjoshua)
July 29, 2020, 3:34pm
5
ok, so i can use variables in the way you suggest above,
and create a value for:
are_all_friendships_mutual: math(incoming == outgoing)
This “works” (returns results comparing the counts), however it is really not the point, as that only really means that a person has the same number of incoming and outgoing friends. But does not at all indicate that they are explicitly mutual.
MichelDiz
(Michel Diz)
July 29, 2020, 3:58pm
6
Based on this dataset How to construct a query collecting all friends? - #9 by MichelDiz
{
G as var(func: eq(name, "User 7"))
result(func: uid(G)) {
name
allFriends :friend @normalize {
name:name
friend @filter(uid(G)) {
mutual : count(uid)
}
}
}
}
Result
{
"data": {
"result": [
{
"name": "User 7",
"allFriends": [
{
"name": "User 5"
},
{
"mutual": 1,
"name": "User 6"
},
{
"name": "User 1"
}
]
}
]
}
}
gotjoshua
(gotjoshua)
July 29, 2020, 5:25pm
7
MichelDiz:
@filter(uid(G))
thanks, so far! this works perfectly for one user at a time…
how can i get it integrated into an everyone query:
{
everyone(func: eq(dgraph.type, "Person")) {
rootuid: uid
name:name@.
friendships: friendship {
name:name@.
frienduid: uid
friends_friends:friendship {
name:name@.
uid
}
}
}
}
yields:
"everyone": [
{
"rootuid": "0x275c",
"name": "Michael",
"friendships": [
{
"name": "Amit",
"frienduid": "0x2761",
"friends_friends": [
{
"uid": "0x275c",
"name": "Michael"
},
{
"uid": "0x275d",
"name": "Artyom"
},
{
"uid": "0x2763",
"name": "Sang Hyun"
}
]
},
which indicates that Michael and Amit are mutual friends…
but i can’t manage to get an is_mutual field anywhere : (
i also can’t manage to filter the inner friends_friends array using the rootuid.
any ideas?
MichelDiz
(Michel Diz)
July 29, 2020, 5:35pm
8
This query looks like “Who of the friends of my friends is a mutual friend with me”. This should work fine. But as the way I was doing.
gotjoshua:
for one user at a time
Yep, some bulk queries won’t work well. That’s why I have created this ticket Feature: Add foreach() function and FOREACH func in DQL (loops in Bulk Upsert) VOTE! - please take a read to get what is happening. Is a long story.
BTW, the reason I have used a multi-blocks approach here is due to the fact that some variables won’t work in the same block or with multi-levels see Promise a nested block (under construction - I'm still working in the use case)
So, you have to use multi-blocks and do this one by one for now.
PS. BTW you can use cascade on my last query. So you gonna have just the mutual friends
{
G as var(func: eq(name, "User 7"))
result(func: uid(G)) {
name
allFriends :friend @normalize @cascade {
name:name
friend @filter(uid(G)) {
mutual : count(uid)
}
}
}
}
gotjoshua
(gotjoshua)
July 29, 2020, 5:50pm
9
ok, but i am confused about variables (and propagation)…
why doesn’t this show ANY is_mutual info?
{
everyone(func: eq(dgraph.type, "Person")) {
rootuid as uid
name:name@.
friendships: friendship {
name:name@.
frienduid: uid
friends_friends:friendship {
targetuid as uid
name:name@.
is_mutual: math(rootuid==targetuid)
}
}
}
}
and why doesn’t this show ANY friends_friends:
{
everyone(func: eq(dgraph.type, "Person")) {
rootuid as uid
name:name@.
friendships: friendship {
name:name@.
frienduid: uid
friends_friends:friendship @filter(uid(rootuid)) {
targetuid as uid
name:name@.
is_mutual: math(rootuid==targetuid)
}
}
}
}
is it not possible to use uid as a variable?
MichelDiz
(Michel Diz)
July 29, 2020, 6:01pm
10
gotjoshua:
@filter(uid(rootuid))
As I said, this won’t work because of Promise a nested block (under construction - I'm still working in the use case) . The variable won’t propagate in the same block. Only if it is an aggregation.
I’m not sure what you are doing in this query. But as I said, the variable will be empty. So the is_mutual will be ignored.
gotjoshua
(gotjoshua)
July 29, 2020, 6:07pm
11
ah, that was the detail i needed
Thanks!