Trying to write a query with "AND" logic on an edge

Given:

A -[children]> B
A -[children]> C

I want to be able to query for A and only return if:

B.node_key = "b"
C.node_key = "c"

I can’t manage to figure out how to do an “AND” on an edge. Like, A must have an edge ‘children’ to a node that has a value ‘node_key=b’ AND it must have an edge to a node that has a value ‘node_key=c’.

{
  
  var(func: eq(node_key, evil_0)) @cascade {
    v0 as uid,
    dgraph.type,
    c0 as children @filter(eq(node_key, "evil_1")) {
      uid, dgraph.type, process_name
    }
  }
    
  var(func: eq(node_key, evil_0)) @cascade {
    v1 as uid,
    dgraph.type,
    c1 as children @filter(eq(node_key, "evil_3")) {
      uid, dgraph.type, process_name
    }
  }
      
  var(func: uid(v0, v1)) @cascade
  	@filter(uid(v0) AND uid(v1))  
  {
    co as uid,
  }
    
  q(func: uid(co))
    {
    uid,
    dgraph.type,
    children @filter(uid(c0, c1))
    {
      uid, dgraph.type, process_name
    },
  }
}

Here’s an example I’ve tried. I just can’t figure out how to say that both children must exist.

1 Like

I think you are overthinking it.

This should work

{
  v0 as var(func: eq(node_key, evil_0)) @cascade {
    c0 as children @filter(eq(node_key, "evil_1")) {
      process_name
    }
     c1 as children2 : children @filter(eq(node_key, "evil_3")) {
      process_name
    }
  }
    
  q(func: uid(v0)){
    uid
    children @filter(uid(c0, c1)){ # This is a bit unnecessary, but if you need, keep it
      uid
      process_name
    }
  }
}

Explaining the query:

Basically, the block var is checking on the same edge for the two values in an “AND” concept (cascade do the trick). If there are no two children with the given values. It would return empty. But if the values match, the second block returns the parent node.

BTW, if you provide samples with the same structure you have, that would help a lot to help you. Not everyone would pick your issue and work on it fast due to the lack of real context (dataset). If you provide it, fast answers you would get.

Also, avoid using commas (can be problematic to the parse, it is supported but it can increase processing) and too much cascade, unless you know what is happening. Also, in Var blocks, you don’t need obvious values like “dgraph.type” and “uid”, only when you need to “printout” on the response. Unless you wanna check (I mean, make sure) the absence of it using cascade.

Also, you have two blocks doing the same query. I consider it a good practice to use the first block as a reference. e.g.:

 v0 as var(func: eq(node_key, evil_0)) @cascade {
    c0 as children @filter(eq(node_key, "evil_1")) {
      process_name
    }
  }
    
  var(func: uid(v0) @cascade {
    c1 as children @filter(eq(node_key, "evil_3")) {
      process_name
    }
  }

This practice avoids other problems.

The sample I did:

{
   "set": {
      "dgraph.type": "Parent",
      "name": "A",
      "node_key": "evil_0",
      "children": [
         {
            "node_key": "evil_1",
            "dgraph.type": "Child",
            "process_name": "B"
         },
         {
            "node_key": "evil_3",
            "dgraph.type": "Child",
            "process_name": "C"
         }
      ]
   }
}

If you have more questions I’m around.

Cheers.

PS. Please, avoid using wrong tags. You have used GraphQL tag on a GraphQL+- question. This also confuses others.

3 Likes

Thanks very much! Apologies on the tags, I’m new to discuss.

Lots of great info in this answer, I had no idea about the commas for example, and didn’t know I could do multiple aliases on a single edge - but it makes perfect sense in retrospect.

Next time I’ll be sure to provide the mutation I was using to test as well.

1 Like