0

I have a problem when trying to filter based on a stored list of strings. I want to build this list in a sideEffect() and then use it in a subsequent where(without()). I am expecting a list of users excluding user.a1 in the following example, but user.a1 is included.

g.V().hasLabel('user').sideEffect(hasId('user.a1').id().store('exclude')).where(id().is(without('exclude')))
[
    {
        "id": "user.a1",
        "label": "user",
        "type": "vertex"
    },
    {
        "id": "user.b1",
        "label": "user",
        "type": "vertex"
    },
    ...
]

I'm assuming this is happening because Gremlin is checking against the literal string exclude, so how do I get it to check against the IDs stored in the exclude variable instead?

For example, this works:

g.V().hasLabel('user').sideEffect(hasId('user.a1').id().store('exclude')).where(id().is(without('user.a1')))
[
    {
        "id": "user.b1",
        "label": "user",
        "type": "vertex"
    },
    ...
]

EDIT #1

Tried the queries suggested by stephen mallette, but still not getting exactly what I'm looking for (maybe not possible on CosmosDB?).

First of all, apparently filter isn't an available function on CosmosDB:

g.V().hasLabel('user').
  sideEffect(hasId('user.a1').id().store('exclude')).
  filter(id().where(without('exclude')))

ExceptionType : GraphCompileException
ExceptionMessage : Gremlin Query Compilation
Error: Unable to find any method 'filter' @ line 1, column 81. 1
Error(s) Source : Microsoft.Azure.Graphs

The second suggestion resulted in an empty set while the second did work:

g.V().hasLabel('user').hasId('user.a1').
  aggregate('exclude').where(without('exclude'))
[]

g.V().hasLabel('user').
  sideEffect(hasId('user.a1').aggregate('exclude')).
  where(without('exclude'))
[
  {
    "id": "user.b1",
    "label": "user",
    "type": "vertex"
  },
  {
    "id": "user.b2",
    "label": "user",
    "type": "vertex"
  },
  ...
]

The problem is that I want to filter edges using their property values. My real life situation is that I want to combine the following two queries into one if possible: get a set of role vertex IDs and then get users that possess one of the roles and belong in a subset of groups. (Users belong to a group with their role ID within that group set as a property of the user->group belongs_to edge.)

  1. Get set of roles from a role hierarchy (role.2 + all parents)
g.V('role.2').store('roles').
  repeat(__.out('is_under')).emit().store('roles').
  select('roles').unfold().dedup().id()
[
    "role.2",
    "role.1"
]
  1. Get users with the above roles in or above group.B and give them an edge to a different role.
g.V('group.B').
  sideEffect(inE('belongs_to').
    has('role',within('role.1','role.2')).outV().store('users')).
  repeat(__.out('belongs_to')).emit().inE('belongs_to').
    has('role',within('role.1','role.2')).outV().store('users').
  select('users').unfold().addE('has').to(g.V('role.12'))

1 Answers1

0

Here's one way to do it:

g.V().hasLabel('user').
  sideEffect(hasId('user.a1').id().store('exclude')).
  filter(id().where(without('exclude')))

There are a few things you could change depending upon how much this example you created matches your actual needs or if it was simplified because of your question. First, you can probably factor away the sideEffect() because store() itself is technically a side-effect. Second, I wonder if you really want store() there an not aggregate() - where aggregate will greedily gather all ids before moving forward to filter:

g.V().hasLabel('user').
  hasId('user.a1').aggregate('exclude').by(id).
  filter(id().where(without('exclude')))

That of course is a bit of a "do nothing" traversal as you have already filtered out the vertices you don't want with hasId('user.a1'), but again, I'm assuming you have greater complexity in your query at play than what you've demonstrated. I'm simply pointing out Gremlin mechanics.

You could also simplify further if you didn't worry about ids - equality of a vertex will be the same as the id and therefore, the following would be equivalent to the above with less Gremlin steps:

g.V().hasLabel('user').
  hasId('user.a1').aggregate('exclude').
  where(without('exclude'))

When asking questions about Gremlin it's best to add a script that generates sample data so that you can get a tested traversal that matches your needs. In lieu of that I've modified the "modern" graph to include a "weight" label:

gremlin> g.addV('weight').property('v',1.0d)
==>v[13]

where the "v" value matches two weight values for the existing edges of the toy graph. Without filter(), I think that you get into this sort of pattern:

gremlin> g.V().hasLabel('weight').
......1>   aggregate('w').by('v').
......2>   V().hasLabel('person').
......3>   outE().as('x').values('weight').
......4>   where(within('w')).
......5>   select('x')
==>e[8][1-knows->4]
==>e[10][4-created->5]
stephen mallette
  • 45,298
  • 5
  • 67
  • 135
  • Thanks for the suggestions! I went ahead and added the results I got from your queries and more information about the real problem I'm looking to solve. –  Mar 13 '19 at 00:45