How to filter out if edge does not have a property?

is there a possibility to filter items if a edge of this item does not have a property / edge?

example:

I have two likes, both likes have an edge (likedFeedback) that can have a toPerson.

This query

query getAll(){        
  likes (func: type(LikeFeedbackGraphModel)) {              
           dgraph.type      
           likedFeedback
           { 
              uid
              fromPerson { uid }
              toPerson { uid }
           }
     }
}

will give me

{
    "likes": [
      {
        "dgraph.type": [
          "ActivityGraphModel",
          "LikeFeedbackGraphModel"
        ],
        "likedFeedback": {
          "uid": "0x396ba8",
          "fromPerson": {
            "uid": "0x396ba6"
          }
        }
      },
      {
        "dgraph.type": [
          "ActivityGraphModel",
          "LikeFeedbackGraphModel"
        ],
        "likedFeedback": {
          "uid": "0x396ba9",
          "fromPerson": {
            "uid": "0x396ba6"
          },
          "toPerson": {
            "uid": "0x396ba7"
          }
        }
      }
    ]
  }

Now, I would like to filter out the likes that references a likedFeedback with a toPerson, something like:

query getAll(){        
  likes (func: type(LikeFeedbackGraphModel)) @filter(has(likedFeedback.toPerson)) {           
           dgraph.type      
           likedFeedback
           { 
              uid
              fromPerson { uid }
              toPerson { uid }
           }
     }
}

Is that even possible? I tried with @cascade but I couldn’t make it work. can I get some hints?

1 Like

Not sure if I get it, but try something like this

query getAll(){        
  var(func: type(LikeFeedbackGraphModel)) 
     @filter(has(likedFeedback)) @cascade {
           LK as uid
           likedFeedback { 
              toPerson { uid }
           }
     }
  likes(func: uid(LK)){           
           dgraph.type      
           likedFeedback { 
              uid
              fromPerson { uid }
              toPerson { uid }
           }
     }
}
1 Like

No, unfortunately this does not work.

The edge toPerson inside likedFeedback is optional. I want to get rid of the likes to feedbacks with a optional toPerson.

So, of the example json above, where we have 2 likes, I would like to see only

{
        "dgraph.type": [
          "ActivityGraphModel",
          "LikeFeedbackGraphModel"
        ],
        "likedFeedback": {
          "uid": "0x396ba9",
          "fromPerson": {
            "uid": "0x396ba6"
          },
          "toPerson": {
            "uid": "0x396ba7"
          }
        }
      }

and filter out the other one where toPerson is optional.

1 Like

Sorry, but I’m really confused with what you want.

All of them?

This JSON says nothing to me.

How can you tell when it is optional or not?

No problem, I’m thankful you are there to help me!

So, with “Optional” I mean that some node have the edge “toPerson” and some does not have it.

Ok, I try to explain that sample data.

It’s an array of 2 items of LikeFeedbackGraphModel.

Both of them have a “likedFeedback” edge.

The first “likedFeedback” HAS a toPerson, but the second does not have it, because it’s optional to have it.

It is more clear now?

I would use the has filter, like so

 @filter(has(toPerson))

but I want to filter the first level node (the LikeFeedbackGraphModel), not the likedFeedback.

so instead of doing

query getAll(){        
  likes (func: type(LikeFeedbackGraphModel)) {           
           dgraph.type      
           likedFeedback @filter(has(toPerson)) 
           { 
              uid
              fromPerson { uid }
              toPerson { uid }
           }
     }
}

I would like to do

query getAll(){        
  likes (func: type(LikeFeedbackGraphModel)) @filter(has(likedFeedback.toPerson))  {           
           dgraph.type      
           likedFeedback 
           { 
              uid
              fromPerson { uid }
              toPerson { uid }
           }
     }
}

because I want to filter the first level, and not the likedFeedback edge. I tried using cascade but it didn’t work.

That’s really not possible due to DQL’s syntax, Cuz predicates can have dots. If we support this level of filtering the syntax will be different. Something like @filter(has((likedFeedback).toPerson)) or something else.

It is not possible to filter like this in DQL right now. The only way is by doing cascade tho.

The way you are explaining confuses me. Cuz first looks like you don’t wanna the nodes with toPerson and then you say in a way that you want it. Based on your responses I was about to suggest something like

likedFeedback @filter(NOT has(toPerson)) 

PS. Have you tried this?

likedFeedback @filter(has(toPerson) and has(fromPerson) ) 

Yeah, you’re right, I’m dumb. I meant exactly this.

Now, this query works fine.

query getAll(){        
  likes (func: type(LikeFeedbackGraphModel)) {              
           dgraph.type      
          uid
           likedFeedback @filter(NOT has(toPerson)) 
           { 
              uid
              fromPerson { uid }
              toPerson { uid }
           }
     }
}

and as you see I get

 "likes": [
      {
        "dgraph.type": [
          "ActivityGraphModel",
          "LikeFeedbackGraphModel"
        ],
        "uid": "0x39b8bf",
        "likedFeedback": {
          "uid": "0x39b8bd",
          "fromPerson": {
            "uid": "0x39b8bb"
          }
        }
      },
      {
        "dgraph.type": [
          "ActivityGraphModel",
          "LikeFeedbackGraphModel"
        ],
        "uid": "0x39b8c0"
      }
    ]

The problem is that I still get the second like, which I want to exclude.

I should fix that by adding @cascade

query getAll(){        
  likes (func: type(LikeFeedbackGraphModel)) @cascade {              
           dgraph.type      
          uid
           likedFeedback @filter(NOT has(toPerson)) 
           { 
              uid
              fromPerson { uid }
              toPerson { uid }
           }
     }
}

but instead, by doing this I’ll get 0 likes, empty array.

Maybe I understood wrongly how @cascade should work?

Cascade will remove from the result all of those who hasn’t all given predicates in the body of the query. Which means, in your query you are asking for both fromPerson and toPerson. So it will fall cuz you also have a NOT filter toPerson. Remove the toPerson from the body and you should be good to go.

Not ideal, but I can live with with @cascade for now.

Are filter predicate gonna support nested property in the future?

No plans for now. But there are open tickets about this.