Search code examples
graphgremlinamazon-neptune

Gremlin query to count vertices without a certain edge


I have a Neptune database in AWS with the following graph:

Graph

So there's a user that organizes a party and has created two invitations. But the user has withdrawn one of these invitations.

I'm looking for a query to count the number of invitations that haven't been withdrawn (1 in the case above).

I've found a way to get the invitations (I'm using the Gremlin package for Javascript):

const result = await g
        .V("user#123")
        .inE().hasLabel("createdBy")
        .otherV()
        .toList();

But I can't seem to find anything to filter those invitations out that have been withdrawn. I don't think I can traverse to the edges that are not withdrawnBy because that would still return 2 (because we have a createdBy and a withdrawnBy edge).

Anyone have any pointers? I've found this answer, which recommends:

gremlin> g.V.filter{!it.bothE('knows').hasNext()}

This is Groovy I assume, but I'm using Javascript (Typescript actually). I've tried the .filter() function, but this seems to throw an error:

.filter(function(this: any) {
    return !this.bothE("isRevokedBy");
})

Solution

  • You can do it like this:

    g.V("user#123").as('u').
      in('createdBy').
      not(where(out('withdrawnBy').as('u')))
    

    example: https://gremlify.com/crjfj88qrtfd8

    But I think it will better to add a property on the createdBy edge that indicates that is been revoke instead of adding another edge between them.

    like this:

    g.V("user#123").
      inE('createdBy').not(has('withdrawn', true)).outV()
    

    example: https://gremlify.com/csfdv6w7325mb

    As you're using the JavaScript package, this is code that would work:

    const gremlin = require("gremlin");
    const __ = gremlin.process.statics;
    const traversal = gremlin.process.AnonymousTraversalSource.traversal;
    const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
    const dc = new DriverRemoteConnection("ws://localhost:8182/gremlin");
    const g = traversal().withRemote(dc);
    
    const result = await g
        .V("user#123")
        .in_("createdBy")
        .where(__.not(__.out("withdrawnBy")))
        .toList()