Traverse Deeply Nested Graph Easily


(Srinath Ganesh) #1

Sample Data:

{'uid': '0xa0', '_Person': '*', 'title': 'Alpha'}
{'uid': '0xa1', '_Person': '*', 'title': 'Bravo'}
{'uid': '0xa2', '_Person': '*', 'title': 'Charlie'}
{'uid': '0xa3', '_Person': '*', 'title': 'Delta'}

Sample Relationships:

Alpha -> Bravo
Bravo -> Charlie
Charlie -> Delta

Query:

{
   all (func: has(_Person)) 
        @filter(eq(title, Alpha)) {
            uid
            expand(_all_) {
                uid
                expand(_all_) {
                    uid
                    expand(_all_) {
                        uid
                        expand(_all_) {
                            
                        }   
                    }
                }
            }
        }
    }

Result

"all": [
      {
        "uid": "0xa0",
        "friend": [
          {
            "uid": "0xa1",
            "friend": [
              {
                "uid": "0xa2",
                "friend": [
                  {
                    "uid": "0xa3",
                    "_Person": "*",
                    "title": "Delta"
                  }
                ],
                "_Person": "*",
                "title": "Charlie"
              }
            ],
            "_Person": "*",
            "title": "Bravo"
          }
        ],
        "_Person": "*",
        "title": "Alpha"
      }
    ]

Question:

Writing nested expand is fine, but is there a simpler way to achieve this?

Neo4J has something like:
MATCH (p)-[r:1..5]-(q) RETURN p, q


(Michel Conrado (Support Engineer)) #2
{
'_Person': '*',  'title': 'Alpha'
  'friend': {  '_Person': '*', 
     'title': 'Bravo', 'friend': {' _Person': '*',
       'title': 'Charlie', 'friend': {'_Person': '*', 'title': 'Delta'} } }
}

OBS. Never assign a UID manually, the UIDs must be generated by the Dgraph to avoid conflicts. Only if strictly necessary, if you want to update an existing Node.

https://docs.dgraph.io/mutations/#edges-between-nodes

I do not know exactly if I understood the question, but for now there is only this form, via GraphQL + -. There will be support for other languages such as Gremlin.


(Srinath Ganesh) #3

I always use uid to UPDATE a node. Actually UID was in my select statement, so I ended up printing it


(Srinath Ganesh) #4

More clarity of the question.

If I want to search
Me -> friend1 -> friend2 -> … -> friendN

then I have to write expand(_all_) N times right? and there is no easier way


(Michel Conrado (Support Engineer)) #5

I believe I already answered this question. I believe you will have something different from what we have today only when we support other Q languages. Today is the easiest.

If we were to use something like “expand(absolutely_everything”) this would lead to possible performance wastage. Ideally, you should use planned queries when you are on production. You can expand indefinitely, but you’d better do it in a planned way.

But tell me what your difficulty is? What does this blocks you in practice?

btw:

expand () serves to expand predicates, when you use "_all_" inside expand it will try to find all existing predicates of a Node and return them.

https://docs.dgraph.io/query-language#expand-predicates


(Srinath Ganesh) #6

Yes the question is answered,

Problem: I was basically trying to do a multi-level search of a node 10 levels deep the way other graph databases do (neo4j or gremlin) where 10 could be a parameter and it would traverse it.

I think the solutions is clear for me now, to use nested “expands”


(Michel Conrado (Support Engineer)) #7

In my point of view you can do this, you can use most Dgraph functions and directives at all levels of a query block.

First you do a wide search in Root, and in the others you use @filter with a pattern to your liking. You can use eq (Inequality), has (something), regexp, uid_in, AND, OR and NOT and so on.

e.g:


{
 AngelinaInfo(func:allofterms(name@en, "angelina jolie")) {
  name@en
   actor.film {
    performance.film {
      genre {
        name@en
      }
    }
   }
  }

 DirectorInfo(func: eq(name@en, "Peter Jackson")) {
    name@en
    director.film @filter(ge(initial_release_date, "2008"))  {
        Release_date: initial_release_date
        Name: name@en
    }
  }
}

(Michel Conrado (Support Engineer)) #8

Take a look on this https://github.com/dgraph-io/dgraph/issues/2267


(Michel Conrado (Support Engineer)) #9

Hey, see if this can help you too