Gremlin (Neptune) somewhat complex query doesn't show edges properties

330 Views Asked by At

I have a set of data in my DB (AWS Neptune), and I query it using Gremlin (NodeJS).

enter image description here

The data looks like this and I have a query that looks like this:

g.V().hasLabel('group').inE('belongs_to')                       
     .outV().has('user_id', user_id).outE()                           
       .otherV().inE().hasLabel('shared_with')                     
           .outV().has('type', type).aggregate('object_id').fold() 
     .V().hasLabel('user').has('user_id', user_id).inE().hasLabel('shared_with')
         .outV().has('type', type).aggregate('object_id').cap('object_id')
     .unfold().dedup().valueMap().toList();

What I end up with (which is correct) is a list of objects and whom they are shared with, the "whom" can be a user or a group. So that was a good start (took me a while to get it, and I grabbed the main idea from StackOverflow), but I don't get the properties of the edges.

Initially, I had two separate queries, one for objects shared with groups, and one for objects shared with users. That worked fine, but obviously took more time and I had to re-conciliate the two lists I was getting.

I have tried to modify my query putting as('x') behind the edges and the Vertices that I need, but then the select was returning nothing at all. Without the select(), the as() is ignored, and I would get the same data as before.

I initially tried with a .local(__.union()) but that didn't work either. I started Gremlin/Neptune last week, and while I made decent progress, I can only use somewhat simple queries :(

Update:

Here's how I create groups:

let group = await g.addV('group')
                .property('group_id', group_id)
                .property('name', name)
                .property('type', groupType)
                .property('owner', owner)
                .next();

//group_id and owner are UUID.

How I add a user to a group:

t = await g.addV('user')
          .property('user_id', user.id)
          .property('name', user.name)
          .next();

t = await g.V()
          .has('user', 'user_id', user.id)     // Find the user
          .addE('belongs_to')                  // Add a new edge
          .to(g.V().has('group', 'group_id', group_id))
          
// user.id is a UUID

Object creation:

let obj = await g.addV('object')
                .property('object_id', object_id)
                .property('ref', ref)
                .property('type', type)
                .property('owner', owner)                
                .property('creation_time', d.getTime().toString())
                .next();

Sharing with user or group:

t = await g.V().has('object','object_id', object_id).has('owner', owner)
         .addE('shared_with')                // Add a new edge
         .property('read', canRead)
         .property('edit', canEdit)
         .property('share', canShare)
         .to(g.V().has('user', 'user_id', id))  // Find the user to link to
         .next();

// For group: .to(g.V().has('group', 'group_id', id))

1

There are 1 best solutions below

7
On

I wasn't exactly sure what the data you were trying to return was but I gathered that you are looking to answer the question "What objects does this user have access to and what are the permissions?"

If this is the case then the best place to start your traversal from the user vertex from which you can then union() the objects shared with the group to the objects directly shared to the user. Finally, you can project() from the shared_with edges to get the values of the object as well as the edge properties for the permissions.

g.V().has('User', 'user_id', 'A').
union(
    out('belongs_to').inE('shared_with'),
    inE('shared_with')
).project('object', 'permission').
by(outV().valueMap().with(WithOptions.tokens)).
by(valueMap().with(WithOptions.tokens))

The with(WithOptions.tokens) will include the metadata such as the id and label so if this is not needed then you can remove that from the traversal.