I'm using neo4j and cypher.
and have a question about cypher.
there are my results.
result 1)
MATCH (f:Fruit)-[r0]-(a:Animal)-[r1]-(h:Human)-[r2]-(p:Plant) where p.type = 'Flower' RETURN *;
result 2)
MATCH (p:Plant)-[r3]-(t:Threat) where p.type = 'Flower' RETURN *;
-->
There are relationship and graph are drawn.
but, I want combine two result.
Is there any way?
Thank you, 🤦♂️
Yes, there is a way to combine results.
UNION ALL
https://neo4j.com/docs/cypher-manual/current/clauses/union/
then to remove any duplicates; use UNION (without ALL)
In your example:
MATCH (f:Fruit)-[r0]-(a:Animal)-[r1]-(h:Human)-[r2]-(p:Plant)
where p.type = 'Flower'
RETURN p, null as t
UNION ALL
MATCH (p:Plant)-[r3]-(t:Threat)
where p.type = 'Flower'
RETURN p, t
Sample Result:
╒══════════╤════════════════╕
│"p" │"t" │
╞══════════╪════════════════╡
│{"name":3}│null │
├──────────┼────────────────┤
│{"name":3}│{"id":"some_id"}│
└──────────┴────────────────┘
All columns that you return must have the same name so I made a hack on naming "null" as t.
Related
I know it is possible to use regular expressions for property values like for example:
MATCH (n)
WHERE n.SomeProperty =~ 'somestring*'
RETURN n;
What i want is to use regular expression on the property name and check for all the properties which start with a certain string like for example:
MATCH (n)
WHERE n.`SomeProperty*` > 10
RETURN n;
So I want to have all nodes which have a property which begins with 'SomeProperty' and have a value > 10 for this property.
This doesn't seems possible with using regular expressions like in my example. I've tried it and with my research i couldn't find a solution. Does anyone have an idea how to achieve this using another technique ?
Given the following test graph
CREATE (:TestNode {somePropertyOne: 10})
CREATE (:TestNode {somePropertyTwo: 11})
CREATE (:TestNode {somePropertyThree: 12})
CREATE (:TestNode {someOtherProperty: 13})
The following query achieves what you want
MATCH (n)
WHERE ANY(x IN keys(n) WHERE x STARTS WITH 'someProperty' AND n[x] > 10)
RETURN n
╒════════════════════════╕
│"n" │
╞════════════════════════╡
│{"somePropertyTwo":11} │
├────────────────────────┤
│{"somePropertyThree":12}│
└────────────────────────┘
Bear in mind that its really not an optimized query for graphs, so it will be slow on decent size databases.
I created sample nodes as below:
Create (n1:RexNode {someproperty10: 10}),
(n2:RexNode { someproperty11: 11}),
(n3:RexNode {someproperty12: 12})
Then I used this query to return n2 and n3. As you can see n1 starts with someproperty but the value is not greater than 10. The quantifier is ANY so it will only look for at least one property (key of node n) and it will return it.
MATCH (n)
WITH n
WHERE
ANY( k in keys(n)
WHERE k STARTS WITH 'someproperty'
AND n[k] > 10
)
RETURN n
Result:
╒═════════════════════╕
│"n" │
╞═════════════════════╡
│{"someproperty11":11}│
├─────────────────────┤
│{"someproperty12":12}│
└─────────────────────┘
I have a query which supposes to join two results and give the union as output.
MATCH (:Some )-[r*0..1]-> (p:Address) WITH collect(p) AS rows1
MATCH (:Some2)-[r*0..1]-> (pp:Address)
WITH rows1+collect(pp) AS rows2
UNWIND rows2 AS row RETURN row
As you can see the selection has two parts. So it works fine if there is matching data for both queries but if the second part of the match does not return anything then it returns empty. Meaning MATCH (:Some2)-[r*0..1]-> (pp:Address) returns empty then the whole union fails and returns null even if MATCH (:Some )-[r*0..1]-> (p:Address) return values .
How to fix this? Is it a bug in neo4j?
You have not actually asked a question (you have indeed just described the expected behaviour for pattern matching ... namely that if there is no match there is no result) ... but I assume you want a solution ?
MATCH (:Some )-[r*0..1]-> (p:Address)
RETURN p
UNION
MATCH (:Some2 )-[r*0..1]-> (p:Address)
RETURN p
should do the trick. Note that the only thing that matters is that the variables returned are exactly the same (what they contain doesn't actually matter).
Also ... you might want to have a look at what OPTIONAL MATCH does ...
Hope this helps.
Regards,
Tom
Update
CALL apoc.cypher.run("
MATCH (:Some )-[r*0..1]-> (p:Address)
RETURN p
UNION
MATCH (:Some2 )-[r*0..1]-> (p:Address)
RETURN p",{}) YIELD value
RETURN value.p AS result
ORDER BY result;
This simple query should work:
MATCH (s)-[*0..1]->(p:Address)
WHERE s:Some OR s:Some2
RETURN p;
Thanks for your inputs I used following version
MATCH (p:Address)
WHERE exist ((:Some )-[r*0..1]-> (p)) OR ((:Some2 )-[r*0..1]-> (p))
RETURN p;
I have a graph with three node types: NodeX, NodeY, and NodeZ
I have the this cypher query:
MATCH (x:NodeX)-[*]->(d)
WHERE x.Name = 'pqr'
RETURN x,d;
Here (d) may could be either NodeY or NodeZ.
I'm looking to handle different nodetypes separately. Something like:
MATCH (x:NodeX)-[*]->(d)
WHERE x.Name = 'pqr'
WITH d
CASE WHEN typeof(d)=NodeY THEN {MATCH (y:NodeY)-[*]-(z:NodeZ)}
WHEN typeof(d)=NodeZ THEN {MATCH (z:NodeZ)-[*]-(y:NodeY)}
RETURN y,z
y and z correspond to d. Is this possible to do so?
Nodes have "labels", not "types" (the latter term only applies to relationships).
To get the labels of a node, you can use the LABELS() function. So, to test if node n has the label Foo, you can do something like this in Cypher:
CASE WHEN 'Foo' IN LABELS(n) THEN ...
However, the CASE clause cannot contain a MATCH clause.
[EDITED]
In your specific case, something like this query (which assumes that, as you said, the only labels possible for d are NodeY and NodeZ) may work:
MATCH (x:NodeX)-[*]->(d)
WHERE x.Name = 'pqr'
WITH d, CASE WHEN 'NodeY' IN LABELS(d) THEN 'NodeZ' ELSE 'NodeY' END AS otherLabel
MATCH (d)-[*]-(other)
WHERE otherLabel IN LABELS(other)
RETURN d, other;
I wish to use the results of a UNION (n) as a filter for a subsequent match.
MATCH (n:Thing)-<<Insert valid match filters here>>
RETURN n
UNION
MATCH (n:Thing)-<<Insert a different set of match filters here>>
RETURN n;
n feeds into:
MATCH (n)-[:RELTYPE1]->(a:Artifact);
RETURN a;
I would expect to use a WITH statement, but I've struggled to figure out how structure the statement.
MATCH (n:Thing)-<<Insert valid match filters here>>
RETURN n
UNION
MATCH (n:Thing)-<<Insert a different set of match filters here>>
WITH n
MATCH (n)-[:RELTYPE1]->(a:Artifact);
RETURN a;
This was my original attempt, but the WITH is interpreted as the start of subquery of the UNION's second match (which makes sense).
I can see a few inelegant ways to make this work, but what is the proper approach?
I have been looking at your union example and it makes sense to me but I cannot see how I could make it work. But I am certainly not the guy with all of the answers. Is there a reason you couldn't do something like this though...
MATCH (n:Thing)
WHERE n.name = 'A'
WITH collect(n) as n1
MATCH (n:Thing)
WHERE n.name = 'B'
WITH n1 + collect(n) AS both
UNWIND both AS n
MATCH (n)-[:RELTYPE1]->(a:Artifact);
RETURN a;
I want to return the count of the union statement, but I'm having a little trouble with my return statement.
Given a venn diagram, the union is the sum of the "areas" of the two circles minus the intersection between them. I'm trying to emulate this, but I ran into a little trouble because Booleans don't convert into ints.
I'm trying to return something like this:
COUNT(DISTINCT a.name) + COUNT(DISTINCT b.name) - (a.name == b.name)
You can do CASE WHEN a.name = b.name THEN 1 ELSE 0 END (and do sum on that, or something). However, you might have dups if you're doing distinct of the other two--maybe you need to adjust something in the rest of your query to avoid duplicates, if you can give us more detail.
If we assume your original query looked like the first UNION example in the neo4j 2.1.5 cheat sheet:
MATCH (a)-[:KNOWS]->(b)
RETURN b.name
UNION
MATCH (a)-[:LOVES]->(b)
RETURN b.name
Then you can get the count of the number of distinct names in the UNION this way:
OPTIONAL MATCH (a)-[:KNOWS]->(b)
WITH COLLECT(DISTINCT b.name) AS n1
OPTIONAL MATCH (c)-[:LOVES]->(d)
WITH COLLECT(DISTINCT d.name) AS n2, n1
RETURN LENGTH(filter(x IN n2 WHERE NOT (x IN n1))) + LENGTH(n1)
I don't see a way to use an actual UNION statement to calculate the answer.
This may be a bit more cypher than you planned to write but I was recently in a similar situation and I ended up putting the sets and intersection in collections and figuring out the resulting difference.
I am sure there is a better way but this is what i came up with. Essentially, I found set 1 and set 2 and put them each in a collection. Then I found the intersection by finding all of the things that were the same and put them in another collection called the intersection. then I just filtered down each of set1, and set2 against the intersection. In the end I am left with two sets that contain the nodes out of the intersection.
match (things_in_set_1)
where <things in set 1 criteria>
with collect(things_in_set_1.name) as set1
match (things_in_set_2)
where <things in set 2 criteria>
with collect(things_in_set_2.name) as set2, set1
optional match (things_in_set_1),(things_in_set_2)
where things_in_set_1.name = things_in_set_2.name
with collect(things_in_set_1.name) as intersection, set1, set2
with filter( id IN set1 WHERE not(id in(intersection)) ) as set_unique_nodes1, set2, intersection
with filter( id IN set2 WHERE not(id in(intersection)) ) as set_unique_nodes2, set_unique_nodes1
return length(set_unique_nodes2) + length(set_unique_nodes1)