The Tables view allows for a familiar tabular look at the contents of a workspace, and also lets you select some relational columns like "path", "parent", and incoming/outgoing references. However, things get complicated if you want a gremlin query to produce a similar result, either to serve as a starting point or in order to export data into an excel-file.

By defining some reusable functions, you can easily create a query that lets you emulate a table view, and then expand upon it to create more complex tabular outputs:


Note: There are some limitations with this approach to be aware of:

  • Workspace names cannot be seen in the graph, so the “path”-column will not be an exact replica.

  • If you add more than nine columns, the column order becomes unpredictable due to data optimizations in Gremlin.

Helper Functions

Reference-columns

Perhaps the most interesting helper function to add is the “relational” columns that show referenced components:

def outgoing = {
out(it).values('name').fold().map{it.get().join(', ')}
}
def incoming = {
__.in(it).values('name').fold().map{it.get().join(', ')}
}

This creates a comma-separated list of referenced components (by name). Note that the incoming-function starts with “__.in”. This is because “in” is a reserved keyword in Groovy, and would cause an error if you tried to invoke it in a “sub-traversal”.

Parent column

You can also find the parent by reusing the “outgoing”-function, or create a separate function for readability:

def parent = {
coalesce(out('ardoq_parent').values('name'), constant(''))
}

Field columns

Next, add a function that safely returns a field value even if the field is missing:

def v = {
__.coalesce(values(it), constant(''))
}
// For numbers, so they get a default of 0 instead:
def n = {
__.coalesce(values(it), constant(''))
}

This works for most fields, but there are some exceptions.

There is the date-range field which is two data-entries grouped together into one column:

def dateRange = {
dateStart = it + '_start_date';
dateEnd = it + '_end_date';
return {
it.property(dateStart).orElse('') + ' - ' + it.property(dateEnd).orElse('')
}
}

There is the SelectMultipleList-field, which in Gremlin is encoded as a Stringified list that should be broken apart. Here’s a regex-method:

def multiSelect = {
fieldName = it
return {
(it.property(fieldName).orElse('') =~ /"(.*?)"/).findAll().collect{it[1]}.join(', ')
}
}

Path column

There is the “path”, which is a list of the parent components separated by an arrow. (NB: Workspace name is not available in the graph)

def path = {
emit().repeat(out('ardoq_parent')).
values('name').fold().
map{it.get().reverse().join(' > ')}
}

Tags

You can also include tags. Since a component can have multiple tags, you'll need to make a slight adjustment to the “v”-function:

def tags = {
values('tags').fold().map{it.get().join(', ')}
}

Putting It All Together

With helper functions defined, you can now put it all together to create a tabular output. Here’s an extreme case that includes all the functions in our toolkit:

def outgoing = {
out(it).values('name').fold().map{it.get().join(', ')}
}
def incoming = {
__.in(it).values('name').fold().map{it.get().join(', ')}
}
def dateRange = {
dateStart = it + '_start_date';
dateEnd = it + '_end_date';
return {
it.property(dateStart).orElse('') + ' - ' + it.property(dateEnd).orElse('')
}
}
def multiSelect = {
fieldName = it
return {
it.property(fieldName).orElse('')//.substring(2)
}
}
def v = {
__.coalesce(values(it), constant(''))
}

def parent = {
coalesce(out('ardoq_parent').values('name'), constant(''))
}

def path = {
emit().repeat(out('ardoq_parent')).
values('name').fold().map{it.get().reverse().join(' > ')}
}

def tags = {
values('tags').fold().map{it.get().join(', ')}
}

g.V().hasLabel('Application').
project('Ardoq Id', 'name', '-> Is integrated with', '<- Is Realized By', '<- Owns', 'Live', 'Active?', 'Use case', 'Missing value', 'Parent', 'Path', 'Tags', 'Component type').
by('component-key').
by('name').
by(outgoing('Is Integrated With')).
by(incoming('Is Realized By')).
by(incoming('Owns')).
by(dateRange('live')).
by(v('active')).
by(multiSelect('use_case')).
by(v('missing')).
by(parent()).
by(path()).
by(tags()).
by(label)

What About The Reference Table View?

Replicating a reference table view is also pretty straight forward, but does require some modifications.

First, instead of selecting components (vertices), we instead select references (edges):

g.E()...

Then introduce two new helper functions for selecting the incoming and outgoing component:

def source = {
outV().values('name')
}
def target = {
inV().values('name')
}

Also, tags are stores slightly different on references due to a gremlin limitation ("multi-properties" are not available for edges), so you can rewrite the tags-helper:

def tags = {
coalesce(values('tags'), constant([])).map{it.get().join(', ')}
}

These changes now show a "reference table"-style output:

Did this answer your question?