Recursion and merging found nodes into a flat list

As I’m a DQL beginner, I’ve currently two “problems” which can be solved at application
level, but I’d like to learn if there are more elegant ways to do it directly in the
query. I tried several ways to accomplish it, but there seems to be some kind of
misunderstandings between dgraph and the component sitting in front of the keyboard…

Maybe someone can push me into the right direction. Here we go:

Problem 1:

I’ve a query which acts on a given root node (0x01 in this case) and retrieves
devices and sub nodes on that “level”. Maybe comparable to a tree like UI component,
where the user opens a node, and the next level appears.

{
    q(func: uid(0x01)) {
      device {
        name
        type
        serial
      }
      node {
        name
        type
        description
      }
}

The response is

    "q": [
      {
        "device": [
          {
            "name": "Device 1",
            "type": "Device",
            "serial": "A000001"
          },
          {
            "name": "Device 2",
            "type": "Device",
            "serial": "A000002"
          }
        ]
        "node": [
          {
            "name": "Sub 1",
            "type": "Container"
          },
          {
            "name": "Sub 2",
            "type": "Container"
          }
        ]
      }
    ]
  }

Is it possible to get back the nodes and devices on one level like so:

     "q": [
      {
        "objects": [
          {
            "name": "Device 1",
            "type": "Device",
            "serial": "A000001"
          },
          {
            "name": "Device 2",
            "type": "Device",
            "serial": "A000002"
          },
          {
            "name": "Sub 1",
            "type": "Container"
          },
          {
            "name": "Sub 2",
            "type": "Container"
          }
        ]
      }
    ]
  }

Problem 2:

Same problem like 1, but with recursion. I’d like to be follow the node edges and collect all node/device thingies into a flat list.

For the first problem, the solution that comes to mind is having an objects edge instead of node and devices edge since you anyway have a type edge which tells you the type of the object. Then you could do something like.

{
    q(func: uid(0x01)) {
      objects {
        name
        type
        serial
        description
      }
}

For problem 2, you could use recurse with multiple query blocks. The first query would recursively get all the uids for all objects that are children of the node with uid 0x01. Then the second query can fetch their properties.

{
    var(func: uid(0x01)) @recurse {
      o as objects
    }
    
   q(func: uid(o)) {
      name
      type
      serial
      description   
   }
}
1 Like

Thanks for your answer Pawan! I already thought about moving all nodes to objects, but I had to change some edges to be “reversed”. Did it finally and it works now.

Just ran into another one with recursion where I don’t know how to nest the queries:

I’m searching for certain locations within a bounding box like this:

q(func: within(position, [[[7.9399, 51.4562],[8.0734, 51.4562],[8.0734, 51.3093],[7.9399, 51.3093],[7.9399, 51.4562]]] ))
    		@filter(regexp(name, /foobar/) AND eq(type, "Location")) {
    		uid
    		name
    		type
  		}

Now, I’d like to only return these nodes, that have a unique parent node within the graph. For a single node, I can use shortest to see if there is a path at all:

path as shortest(from: <the parent node>, to: <the node to test>) {
	objects
}
path(func: uid(path)) {
        name
}

Is it possible to create a query that returns all nodes inside the bounding box, which have a path to a given parent node? In tree words: can I query for all objects within a subtree which are inside the bounding box?

Perhaps you are looking for an intersection here which can be done using AND filter

{
    var(func: uid(<the_parent_node>)) @recurse {
      o as objects
    }

    q(func: within(position, [[[7.9399, 51.4562],[8.0734, 51.4562],[8.0734, 51.3093],[7.9399, 51.3093],[7.9399, 51.4562]]] )) 
      @filter(uid(o) AND regexp(name, /foobar/) AND eq(type, "Location")) {
      uid
      name
      type
    }
}

Thanks for your help @pawan. That works. I didn’t recognize that the query results inside O can be used within @filter(uid(O))

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.