Search code examples
gremlin

Gremlin query for nodes that all outgoing edges are related to a given list list


I have a graph schema: ( Person )-- Adopted --> ( Cat )<-- Parent_Of --( Cat )

Given a list of cats, I want to find people that all their adopted cats are from the list, OR sons of cats from the list.

We can assume that every person adopted at least one cat.

For example: Pat Adopted Felix and Simba. Simba is the son of Sarabi.

If I query for Felix and Sarabi, I want to find Pat.

If I query for Felix and Simba, I want to find Pat.

If I query for Felix only, I don't want to find Pat.

My query for Felix and Sarabi is:

g.V().hasLabel('Person').where( 
    out('Adopted').not(
        or(
            hasLabel('Cat').has('name','Felix'),
            hasLabel('Cat').has('name','Sarabi'),
            __.in('Parent_Of').hasLabel('Cat').has('name','Felix'),
            __.in('Parent_Of').hasLabel('Cat').has('name','Sarabi'),
        )
    ).count().is(eq(0))
).properties('name')

This is correct, but unintuitive and very inefficient, especially when querying many cats, where each cat has a lot of children.


Solution

  • If this is helpful to somebody, the solution I found was:

    g.V().or(
        hasLabel('Cat').has('name','Felix'),
        hasLabel('Cat').has('name','Sarabi'),
    ).union( identity() , out('Parent_Of') ).aggregate('cats').fold() \
    .V().hasLabel('Person').where( 
        out('Adopted').where( without( 'cats' ) ).count().is(eq(0)) 
    ).properties('name')