Variables in child block

I am struggling with understanding how passing variables to child works. I am trying a query that (in my perception) is very similar to an example from A Tour of DGraph

In essence, I am trying to detect a loop of edges between four nodes: [dest_ip] -> [Flow] -> [src_ip] -> [DNS] -> [dest_IP]. When running the following query, I can see that there must exist one of those loops (see the matching uids of the destination IP address nodes):

{
  loop(func: eq(dgraph.type, "Flow"), offset: 1, first: 1) { # Flow node    
    dest_ip { # destination IP node
      uid
    }
    src_ip { # source IP node 
      uid
      ~requesting_ip {  # edge to DNS node
        uid
      	resolved_ip { # destination IP node again
          uid
        }
    	}
    }
  }
}

gives as answer:

"loop": [
      {
        "dest_ip": {
          "uid": "0x5368a"
        },
        "src_ip": {
          "uid": "0x535b5",
          "~requesting_ip": [
            {
              "uid": "0x53769",
              "resolved_ip": [
                {
                  "uid": "0x5368a"
                }
              ]
            }
          ]
        }
      }
    ]

My attempt at filtering on the uid of the destination address does not result in the expected answer:

  loop(func: eq(dgraph.type, "Flow"), offset: 1, first: 1) { # Flow node    
    dest_ip_node as dest_ip {  # destination IP node
      uid 
    }     
    src_ip { # source IP node
      uid
      ~requesting_ip { # edge to DNS node
        uid
        resolved_ip @filter(uid(dest_ip_node)) { # desination IP node again
        	uid
        }
      }
    }  	
  }    
}

gives the answer:

"loop": [
      {
        "dest_ip": {
          "uid": "0x5368a"
        },
        "src_ip": {
          "uid": "0x535b5",
          "~requesting_ip": [
            {
              "uid": "0x53769"
            }
          ]
        }
      }
    ]

An almost identical answer, but without the resolved IP.

I would love to know what is wrong with the second query.

Can you try:


 loop(func: eq(dgraph.type, "Flow"), offset: 1, first: 1) { # Flow node    
    dest_ip_node as dest_ip   # destination IP node   
    src_ip { # source IP node
      uid
      ~requesting_ip { # edge to DNS node
        uid
        resolved_ip @filter(uid(dest_ip_node)) { # desination IP node again
        	uid
        }
      }
    }  	
  }    
}

You have to do in two separated blocks. e.g:

{
ORIGIN as var(func: eq(dgraph.type, "Flow"), offset: 1, first: 1) { 
    uid
    dest_ip_node as dest_ip   # destination IP node   
 }

loop(func: uid(ORIGIN) { # Flow node    
    src_ip { # source IP node
      uid
      ~requesting_ip { # edge to DNS node
        uid
        resolved_ip @filter(uid(dest_ip_node)) { # desination IP node again
        	uid
        }
      }
    }  	
  }    
}

I have mentioned about this at Promise a nested block (under construction - I'm still working in the use case)

1 Like

Thanks for the provided answer @MichelDiz. However, it doesn’t seem to work completely the way I’m expecting it to do. I adjusted your answer-query a bit to illustrate what is going on:

{
  ORIGIN as var(func: eq(dgraph.type, "Flow"), offset: 0, first: 10) {     
    uid
    dest_ip_node as dest_ip   # destination IP node   
  }

  loop(func: uid(ORIGIN)) @cascade { # Flow node    
    dest_ip {
      uid
    }
    src_ip @cascade { # source IP node
      uid
      ~requesting_ip @cascade { # edge to DNS node
        uid
        resolved_ip @filter(uid(dest_ip_node)) @cascade { # desination IP node again
       	 uid
        }
      }
    }  	
  }    
}

Adding some @cascade statement to filter out non-matching values. Most of the responses are what I expect:

{
  "dest_ip": {
    "uid": "0x5368a"
  },
  "src_ip": {
    "uid": "0x535b5",
    "~requesting_ip": [
      {
        "uid": "0x53769",
        "resolved_ip": [
          {
            "uid": "0x5368a"
          }
        ]
      }
    ]
  }
}

As you can see, the uid of dest_ip equals the uid when traversing the src_ip -> ~requesting_ip -> resolved_ip edges, which is exactly the preferred answer. However, there are some answers in which is not the case:

{
  "dest_ip": {
    "uid": "0x535e1"
  },
  "src_ip": {
    "uid": "0x5366c",
    "~requesting_ip": [
      {
        "uid": "0x536e9",
        "resolved_ip": [
          {
            "uid": "0x5368a"
          }
        ]
      }
    ]
  }
}

In this answer, the IP uids do not match, but the uid of the resolved_ip matches another flow’s destination address (more specifically the uid fo the dest_ip node of the previous example response I wrote down above), which is what I am not looking for.

This should work as expected. Because in both blocks we are using the same UID, and dest_ip_node belongs to that node that we find in both blocks.

Maybe the problem is different, maybe dest_ip_node is capturing multiple UIDs. And don’t show others because of the cascade. Check if you can find multiple nodes. And if It had “0x535e1” before (can be a bug with delation).