Concatenating details with specified property key

Hey all, I'm trying to get an array of objects back from Gremlin that looks like the following:
[{
id: 1,
label: "ServiceGroup",
name: "MyServiceGroup"
services: [{ id: 2, name: "MyService" }]
}]
[{
id: 1,
label: "ServiceGroup",
name: "MyServiceGroup"
services: [{ id: 2, name: "MyService" }]
}]
Where id, label and name are the result of valueMap(true), but services are a result of a out('hasService').hasLabel('Service').fold() for each service group. I managed to come close by doing a project:
g.V().hasLabel('ServiceGroup').project('properties', 'services').by(valueMap(true)).by(out('hasService').hasLabel('Service').fold()).toList()
g.V().hasLabel('ServiceGroup').project('properties', 'services').by(valueMap(true)).by(out('hasService').hasLabel('Service').fold()).toList()
However that ends up with a properties object that I do not want. What can I do to be able to get the above object? I thought about trying unions, but was not successful - maybe I didn't use it correctly. Any advice would be appreciated. Thanks in advance!
Solution:
A minor point on your attempt to statically produce the output you wanted, but it is considered better form to use tokens when you can in the by() modulators: ```groovy g.V().hasLabel('ServiceGroup'). project('id', 'label', 'name', 'services')....
Stack Overflow
Merging maps in Gremlin
I'm trying to write a single query that satisfies two requirements in the response object: Must include all properties of a vertex, without specifying individual fields in the query. Must flatten
stephen mallette
Static and Dynamic Map Instances
This is an interesting piece of Gremlin:
Jump to solution
11 Replies
Shush
Shush17mo ago
I have managed to get my intended result with manual specification of each key:
g.V().hasLabel('ServiceGroup').project('id', 'label', 'name', 'services')
.by(id())
.by(label())
.by(values('name'))
.by(out('hasObject').hasLabel('Service').valueMap(true).fold())
g.V().hasLabel('ServiceGroup').project('id', 'label', 'name', 'services')
.by(id())
.by(label())
.by(values('name'))
.by(out('hasObject').hasLabel('Service').valueMap(true).fold())
However I would like it to fill the id, label and name and all other properties automatically, similarly to how valueMap(true) would do so, and then add services to it.
Solution
spmallette
spmallette17mo ago
A minor point on your attempt to statically produce the output you wanted, but it is considered better form to use tokens when you can in the by() modulators:
g.V().hasLabel('ServiceGroup').
project('id', 'label', 'name', 'services').
by(id).
by(label).
by('name').
by(out('hasService').hasLabel('Service').fold())
g.V().hasLabel('ServiceGroup').
project('id', 'label', 'name', 'services').
by(id).
by(label).
by('name').
by(out('hasService').hasLabel('Service').fold())

Since you want your properties to be generated dynamically, your Gremlin sort of gets more complicated because you will need deconstruct and reconstruct the resulting Map:
g.V().
hasLabel('ServiceGroup').
map(union(project('services').by(out('hasService').hasLabel('Service').fold()),
valueMap(true)).
unfold().
group().by(select(keys)).by(select(values)))
g.V().
hasLabel('ServiceGroup').
map(union(project('services').by(out('hasService').hasLabel('Service').fold()),
valueMap(true)).
unfold().
group().by(select(keys)).by(select(values)))
This pattern is discussed in a few places if you'd like to do more reading: https://stackoverflow.com/a/60307857/1831717 https://tinkerpop.apache.org/docs/current/recipes/#collections https://stephen.genoprime.com/snippet/2020/02/29/snippet-4.html
Stack Overflow
Merging maps in Gremlin
I'm trying to write a single query that satisfies two requirements in the response object: Must include all properties of a vertex, without specifying individual fields in the query. Must flatten
stephen mallette
Static and Dynamic Map Instances
This is an interesting piece of Gremlin:
Shush
Shush17mo ago
A minor point on your attempt to statically produce the output you wanted, but it is considered better form to use tokens when you can in the by() modulators:
Interesting, why is that?
spmallette
spmallette17mo ago
tokens perform better than anonymous traversals on many graph systems
Shush
Shush17mo ago
Oh, I see. So essentially it's better to just pick the fields you know you'll need?
spmallette
spmallette17mo ago
sorry, maybe i'm confusing you. i'm just saying that it's considered better form to do by(id) than by(id()) the first is T.id a token and the second is __.id() an anonymous traversal
Shush
Shush17mo ago
oh, I missed that
spmallette
spmallette17mo ago
you used the latter in your example so i was just trying to point that out
Shush
Shush17mo ago
by using id rather than id() it will still print the id of the vertex, but as a token? Seems like it, yeah Good to know! We're definitely using id() and label() literally everywhere, lol
spmallette
spmallette17mo ago
it may not matter for you from a performance perspective. don't go changing all your code without doing some tests. i just tend to call it out because i think it looks nicer and there is a chance you make your Gremlin a bit faster here/there. fwiw, there are optimizers that will find those anonymous traversals and convert them for you, but i prefer to write Gremlin in a form where optimizers have to do the least amount of work
Shush
Shush17mo ago
That makes sense. Our code is very old (2-3 years old) and it generally is working pretty well, so I probably won't change it for existing locations unless I'm doing some changes in those areas anyway Thank you for taking the time for the detailed answer, the dynamic pattern is excellent, I have been going crazy trying to get it right for a few hours. Appreciate it!