Although one of the most common use cases for demonstrating the capabilities of a graph database, I cannot seem to find a good example or best practice for obtaining \"friends o
Have you tried this?
select
expand(bothE('is_friend_with')[status = 'approved'].inV().bothE('is_friend_with')[status = 'approved'].inV())
from user where uuid = '95920a96a60c4d40a8f70bde98ae1a24'
There may be a nicer way to do it, but I think this gives you what you're looking for:
Setup:
create class User extends V
create class IsFriendsWith extends E
create property User.name string
create property User.uuid string
create property IsFriendsWith.status string
create vertex User set uuid = "1", name = "Bob"
create vertex User set uuid = "2", name = "Sally"
create vertex User set uuid = "3", name = "Eric"
create vertex User set uuid = "4", name = "Jenny"
create vertex User set uuid = "5", name = "Dennis"
create vertex User set uuid = "6", name = "Mary"
create vertex User set uuid = "7", name = "John"
create edge IsFriendsWith from (select from User where uuid = "1") to (select from User where uuid = "2") set status = "approved"
create edge IsFriendsWith from (select from User where uuid = "1") to (select from User where uuid = "3") set status = "pending"
create edge IsFriendsWith from (select from User where uuid = "2") to (select from User where uuid = "4") set status = "approved"
create edge IsFriendsWith from (select from User where uuid = "5") to (select from User where uuid = "2") set status = "pending"
create edge IsFriendsWith from (select from User where uuid = "3") to (select from User where uuid = "4") set status = "approved"
create edge IsFriendsWith from (select from User where uuid = "6") to (select from User where uuid = "1") set status = "approved"
create edge IsFriendsWith from (select from User where uuid = "6") to (select from User where uuid = "7") set status = "approved"
Query:
select from (
select
expand(unionall(
outE("IsFriendsWith")[status="approved"].inV(),
inE("IsFriendsWith")[status="approved"].outV()
))
from (
select
expand(unionall(
outE("IsFriendsWith")[status="approved"].inV(),
inE("IsFriendsWith")[status="approved"].outV()
))
from (
select from User where uuid = "1"
)
)
)
) where uuid <> "1"
Enrico's answer won't give you quite what you're after because it only takes into account edges in one direction when it needs to work both ways.
Edit: To exclude people that the user happens to be friends with already, use the following (note that this example assumes the User's RID is #26:0
)
select from (
select
expand(unionall(
outE("IsFriendsWith")[status="approved"].inV(),
inE("IsFriendsWith")[status="approved"].outV()
))
from (
select
expand(unionall(
outE("IsFriendsWith")[status="approved"].inV(),
inE("IsFriendsWith")[status="approved"].outV()
))
from #26:0
)
)
)
where @rid <> #26:0 and @rid NOT IN (select both("IsFriendsWith") from #26:0)
Edit 2: Using variables instead.
select from (
select
expand(unionall(
outE("IsFriendsWith")[status="approved"].inV(),
inE("IsFriendsWith")[status="approved"].outV()
))
from (
select
expand(unionall(
outE("IsFriendsWith")[status="approved"].inV(),
inE("IsFriendsWith")[status="approved"].outV()
))
from (
select expand($u) let $u = first((select from User where uuid = "1"))
)
)
)
)
where @rid <> $u and @rid NOT IN $u.both("IsFriendsWith")
This should be much simpler:
select expand(
bothE('is_friend_with')[status = 'approved'].bothV()
.bothE('is_friend_with')[status = 'approved'].bothV()
) from user where uuid = '95920a96a60c4d40a8f70bde98ae1a24'
With bothE() and then bothV() you get both in/out connections at edge/vertex level.
In order to exclude current user you could use:
select expand(
bothE('is_friend_with')[status = 'approved'].bothV()
.bothE('is_friend_with')[status = 'approved'].bothV()
.remove( @this )
) from user where uuid = '95920a96a60c4d40a8f70bde98ae1a24'