Search code examples
gremlingraph-databasesamazon-neptune

Gremlin query - how to eliminate nested coalesce


I have person vertex, has_vehicle edge and vehicle vertex which models vehicle ownership use case. The graph path is person -> has_vehicle -> vehicle.

I want to implement a Gremlin query which associates a vehicle to a person only if

  • The person does not have a vehicle

AND

  • The input vehicle is not associated with a person yet.

I followed the fold-coalesce-unfold pattern and came out with following Gremlin query with nested coalesce

g.V().hasLabel('person').has('name', 'Tom').as('Tom').outE('has_vehicle').fold().coalesce(
  __.unfold(), // check if Tom already have a vehicle
  g.V().has('vehicle', 123).as('Vehicle').inE('has_vehicle').fold().coalesce(
    __.unfold(), // check if vehicle 123 is already associated with a person
    __.addE('has_vehicle').from('Tom').to('Vehicle') // associate the vehicle to Tom
  )
)

Is there a way to eliminate the nested coalesce? If I have multiple criteria, it would be too complex to write the query.


Solution

  • This might be a case where a couple of where(not(...)) patterns, rather than nesting coalesce steps works well. For example, we might change the query as shown below.

    g.V().hasLabel('person').has('name', 'Tom').as('Tom').
          where(not(outE('has_vehicle'))).
      V().has('vehicle', 123).as('Vehicle').
          where(not(inE('has_vehicle'))).
      addE('has_vehicle').from('Tom').to('Vehicle')
    

    So long as the V steps do not fan out and yield multiple Tom or Vehicle nodes that should work and is easy to extend by adding more to the where filters as needed.

    As as a side note, the not steps used above should work even if not wrapped by where steps, but I tend to find it just reads better as written.

    This rewrite does make an assumption that you are able to tolerate the case where Tom already has a car and the query just ends there. In that case no vertex or edge will be returned. If you did a toList to run the query you would get an empty list back in that case however to indicate nothing was done.