I have a query that returns a set of nodes, like this:
g.V().as("a","node").has("prop1", true).out().as("b","node").hasLabel("device")
.in().as("c","node").hasLabel("lbl1").has("prop1", false).select("a","b","c").limit(200)
Now I want to return all these nodes and any edge between them as my result. I tried the following but it always comes back empty:
g.V().(....)
.select("a","b","c").limit(200)
.select("node").dedup().fold().as('all')
.unfold().as('start').bothE().as('edge').otherV().as('end')
.where(within('all'))
.select('start', 'edge', 'end').dedup()
unfortunately this always comes back empty. I think my where filter is incorrect. How do I filter the result for only those where node "c" is one of those in "a"?
I want to keep this generic so I can use it to process multiple different queries that all return a set of nodes.
For this query, you should check that out vertex is in the set of the beginning vertex. So you should first fold() the start set and then check against it with within() predicate inside where
Here is query for example g = TinkerFactory.createModern().traversal()
g.V().limit(3).fold().as('all').
unfold().as('a').outE().as('b').otherV().as('c').
where(within('all')).
select('a', 'b', 'c')
See 2nd example here: https://tinkerpop.apache.org/docs/current/reference/#where-step
Related
I have a query written out where one of the lines is as follows:
[individualNode IN listOfNodes | [(individualNode)-[:CONNECTED_WITH]->(otherNode) | {node:otherNode, similarity:individualNode['similarity']}]] AS connectionMap
listOfNodes is a List of maps
Example of one of the map in the list is
{
"similarity":0.25,
"node":{
"identity":12345,
"labels": [
"Label1",
"Label2"
],
"properties": {
yada..yada..
}
}
The issue here is that since individualNode is a map the statement (individualNode)-[:CONNECTED_WITH]->(otherNode) will fail.
So my question is how do i access the node to use in the match statement, but still retain the map so i can grab the similarity value.
Disclaimer: I know node is a special word in cypher, i only used it here so you guys know what it is i am talking about in the map. That's not how it is in my actual query.
I also change the names of things because i cannot reveal the actual information in the map.
I have tried to write it as (individualNode.node)-[:CONNECTED_WITH]->(otherNode) or (individualNode['node'])-[:CONNECTED_WITH]->(otherNode) but both throw errors too.
Do you want to use it later?
You can access maps with their keys, e.g. map.node
if you want to use that in a pattern you have to alias it with an identifier
e.g. WITH map.node as startNode MATCH (startNode)-->(...)
if you have a list of nodes like in your case you either can walk through that in a pattern comprehension again, like you already did
or you can use UNWIND to turn the list into rows.
UNWIND listOfNodesMaps as map
WITH map.node as startNode, map.similarity as similarity
MATCH (startNode)-->(...)
My graph has the following edges:
e[1][0--classes->1]
e[2][0--classes->2]
e[3][0--classes->3]
and nodes 1,2,3 have property classId 1,2 and 3 respectively.
I want to write a query to return all pairs (m,n) such that m.classId < n.classId. The following is my closest attempt thus far:
g.V(0).out("classes")
.as_('n').classId.as_('nid')
.select('n').in_("classes").out("classes")
.as_('m').classId.where(lte(select('nid')))
.select('m', 'n')
Unfortunately, lte expects a number while select('nid') is a traversal. I have tried various variants of inputs to both the .where and is_ traversals, but haven't had any joy.
You don't need to use select inside lte step. you can use the named "nid" without it.
You were also missing by modulator:
g.V().hasLabel('0').out('classes').as('n').
as('nid').select('n').
in('classes').out('classes').as('m').
where(lte('nid')).
by('classId').
select('m', 'n')
example: https://gremlify.com/bu789rfvme89q
From a traverser, if I just want the first item in the list of vertexes, how would I go about returning it as an object?
I've tried:
g.V()
.has("Project", "id", eq("someid"))
.outE("Contains")
.inV()
.hasLabel("Goal")
.sample(1)
.values("name")
Also tried:
g.V()
.has("Project", "id", eq("someid"))
.outE("Contains")
.inV()
.hasLabel("Goal")
.limit(1)
.values("name")
I've also tried fold but none of them worked for me. Any ideas?
I'm not quite following what you want but your either traversal should only return one "name" value and not a list of "name" values, though I think I'd prefer the second since you said you want the first item returned. I'd re-write it as follows though:
g.V().has("Project", "id", "someid").
out("Contains").hasLabel("Goal").
values("name")
limit(1)
You just pasted some Gremlin here, but you can also next() the Iterator to get that single first object:
String name = g.V().has("Project", "id", "someid").
...
limit(1).next()
If you're seeing some other behavior for some reason in the return values please update your question to include a sample data script (example) so that it's easy to reproduce in the Gremlin Console.
This sounds silly but is there a way to create a empty array inside a Gremlin traversal?
For the query below:
g.V().has('person','name', 'marko').project('a', 'b').by().by()
I want to project b as an empty array. I have tried:
g.V().has('person','name', 'marko').project('a', 'b').by().by(constant("").fold())
But constant("").fold() is not actually empty constant("").fold().count() returns 1. This applies to constant(null).fold() as well.
Is this what you are looking for
g.withSideEffect('x',[]).V().has('person','name','marko').project('a','b').by(select('x')).by('name')
==>[a:[],b:marko]
An empty array/collection would actually be a fold() of nothing. You'll get nothing if you filter everything, hence:
g.V().has('person','name','marko').
project('a', 'b').
by().
by(__.not(identity()).fold())
I have a forest of nodes and relationships. Similar to the following:
N1-sends->N2-sends->N3-sends->N4
N5-sends->N6-sends->N7-sends->N8
N9-sends->N10-sends->N11-sends->N12-sends->N13
I want to write a Cypher query that returns the 3 paths, without the first or last item. The nodes that are NOT at the beginning or end of the paths already have a property("middle", "true"), so that makes it easier.
A problem that I have encountered is that Cypher returns the path and every SUBSET of the path as well. For example it returns n10->n11-> and n11->n2, and n10->n11->n12, .... which is not what I want.
Instead I just want the results to be an array of 3, where inside each I have:
n2->n3
n6->n7
n10->n11->n12
and thats it.
The queries that I have came up with are: (first one has syntax errors):
START n=node(*) MATCH p=()-[*]->i-[*]->() WHERE has(i.middle)
WITH COLLECT(p) AS pa, MAX(length(p)) AS maxLength, NODES(p) AS pn
FILTER(path IN pa WHERE length(path)=maxLength) AS longestPaths
RETURN DISTINCT FILTER(x IN longestPaths WHERE exists(x.middle))
and
START n=node(*) MATCH p=()-[*]->i-[*]->()
WHERE has(i.middle)
RETURN DISTINCT filter(x IN NODES(p) WHERE exists(x.middle)) as O
The second one returns the paths without the first and last node, but it returns duplicated nodes, because it returns subsets of path as well..
Thank you.
This might do what you want:
MATCH (n)-[:sends*]->(m)
WHERE NOT ( ()-[:sends]->(n) OR (m)-[:sends]->() )
RETURN NODES(p)[1..-1] AS middleNodes;
The WHERE clause eliminates sub-paths (i.e., paths that are part of a longer path). The NODES(p)[1..-1] syntax returns the second through next-to-last nodes in each path.