1

I am new to Gremlin and working with typescript in the Azure Cosmos DB, which means I am not allowed to use all cool new features like sideEffect ...

I have a tree-like scenario, where Vertices are parentOf other Vertices but can only have one own parent and a person which is employed at one vertex.

Here is some example-data for my graph:

g.addV('person').property('partitionKey', 'person').property('accountID','1')
g.addV('unit').property('partitionKey', 'unit').property('unitID', '1')
g.addV('unit').property('partitionKey', 'unit').property('unitID', '2')
g.addV('unit').property('partitionKey', 'unit').property('unitID', '3')
g.V().has('accountID','1').as('p').V().has('unitID','1').addE('employedAt').from('p')
g.V().has('unitID','1').as('u').V().has('unitID','2').addE('parentOf').from('u')
g.V().has('unitID','2').as('u').V().has('unitID','3').addE('parentOf').from('u')

The tree now looks like:

person --- employedAt ---> unit1 --- parentOf ---> unit2 --- parentOf ---> unit3

We now want to make unit2 the child of unit3

Expected result after that:

person --- employedAt ---> unit1 --- parentOf ---> unit3 --- parentOf ---> unit2

We now want to move one vertex around (creating a new incoming parentOf-Edge and drop the old one).

The first block is to check if the person has access to both vertices. It doesn't feel very performant but I don't know how to do it better.

The first statement in coalesce is to move a Vertex down the tree (make it the child of one of his subvertices). Therefore we check if it is the parent of the targetVertex, when it is the parent, then it also does the rest of this coalesce-statement.

The second statement is to move a vertex do another branch in the tree. This will be reached, when it is not the "difficult" part.

// Get the employedAtVertex and store the employedAtVertex
    g.V().has('person', 'accountID', accountID).outE('employedAt').otherV().as('employedAtVertex')
// Check if the employedAtVertex is parentOf the movingVertex and store the movingVertex
    .V().has('id', movingVertexID).as('movingVertex').until(select('employedAtVertex')).repeat(__.in('parentOf'))
// Check if the employedAtVertex is parentOf the targetVertex and store the targetVertex
    .V().has('id', targetVertexID).as('targetVertex').until(select('employedAtVertex')).repeat(__.in('parentOf'))

// ### Coalesce-Step (do the first part if possible, otherwise do the second part)
    .coalesce(
// ### First Part: Make a vertex the children of his own children
// Check if the movingVertex is parentOf the targetVertex
    select('targetVertex').until(has('id', select('movingVertex').values('id'))).repeat(__.in('parentOf'))
// Union the incoming parentOf-Edges in moving- and targetVertex and store them as edgesToDrop
 .union(select('movingVertex').inE().hasLabel('parentOf'),select('targetVertex').inE().hasLabel('parentOf')).as('edgesToDrop')
// Check if the employedAtVertex is parentOf the old parent of the movingVertex and store it as oldParentVertex
    .V().has('id', oldParentOfMovingVertexID).as('oldParentVertex').until(select('employedAtVertex')).repeat(__.in('parentOf'))
// Create parentOf-Edge from oldParentVertex to targetVertex
    .select('targetVertex').addE('parentOf').from('oldParentVertex')
// Create parentOf-Edge from targetVertex to movingVertex
    .select('movingVertex').addE('parentOf').from('targetVertex'),

// ### Second Part: Make a vertex the children of a vertex higher in the tree or in an other branch
// Get the incoming edge in movingVertex and store it as edgesToDrop
    select('movingVertex').inE('parentOf').as('edgesToDrop')
// Create parentOf-Edge from targetVertex to movingVertex
    .select('movingVertex').addE('parentOf').from('targetVertex'))
// ### Ende of Coalesce

// Drop the stored edgesToDrop
    .select('edgesToDrop').drop()

I have a few problems now:

  1. The way I try to drop doesn't work
  2. When I delete the drop-statement it will create (in the first case of coalesce) both edges twice, which totally doesn't make sense to me.
  3. Is there a more performant way to check if the employedAt-Vertex is parent (or grandparent or whatever) of the moving and the targetvertex?
Tobi Hin
  • 11
  • 2
  • 2
    since this is a complex use case I think it will be better if you add a script to generate example data or saved gremlify example. and then give the expected behavior for that data. – noam621 Jul 01 '20 at 10:55
  • Hello, thanks for explaining how to get some help. I have updated my question and put an example in and also the expected result – Tobi Hin Jul 02 '20 at 11:10

2 Answers2

0

I tried to understand the logic from your query and example, I hope that's what you needed.

g.V().has('person', 'accountID', accountID).
  out('employedAt').as('employedAtVertex').

// Check if the employedAtVertex is parentOf the movingVertex and targetVertex
  emit(has('unitID', within(movingVertexID, targetVertexID))).
  repeat(out('parentOf')).
  fold().where(count(local).is(2)).as('vertices').
  unfold().has('unitID', targetVertexID).as('targetVertex').

// Check if the movingVertex is parentOf the targetVertex
  choose(until(has('unitID', movingVertexID)).repeat(__.in('parentOf')),

// ### First Part: Make a vertex the children of his own children
        select('vertices').unfold().has('unitID', movingVertexID).as('movingVertex')
        union(            
            __.in('parentOf').addE('parentOf').to(select('movingVertex').out('parentOf')),
                bothE('parentOf').drop(),
                addE('parentOf').from('targetVertex')
            ),
// ### Second Part: Make a vertex the children of a vertex higher in the tree or in an other branch
        union(
            inE('parentOf').drop(),
            addE('parentOf').from('targetVertex'),
            )
    )
  

example: https://gremlify.com/fuq7sbmvjzv

noam621
  • 2,766
  • 1
  • 16
  • 26
0

The first part works perfect. and the result looks like expected.

I now have a problem with the second part. When I create a tree which looks like:

     person
       |
   employedAt
       |
      unit1
     /     \
parentOf  parentOf
   |         |
unit2      unit4
   |
parentOf
   |
unit3

and ich now want to move unit2 to be the child of unit4 it doesn't work. I have than unitID 2 for movingVertex and unitID 4 for targetVertex

The expected result then will look like:

person
   |
employedAt
   |
unit1
   |
parentOf
   |
unit4
   |
parentOf
   |
unit2
   |
parentOf
   |
unit3

But it doesn't do anything.

Tobi Hin
  • 11
  • 2