I'm trying to run a query which has two parts
start cat=node(21) match cat-[:HAS_KEYWORD]->(word)-[:FOUND_IN]->doc return doc
this query works fine and return the results
start cat=node(21) match cat-[:HAS_KEYWORD]->composit-[:COMPOSITE_OF]->(word)-[:FOUND_IN]-single
this works OK too and retun empty set
but when I combine them
start cat=node(21) match cat-[:HAS_KEYWORD]->(word)-[:FOUND_IN]->doc
with cat,doc
match cat-[:HAS_KEYWORD]->composit-[:COMPOSITE_OF]->xx-[:FOUND_IN]->single
return doc,single
no results returned
what Is wrong with It?
The problem is that you have an empty set here, so the second match brings your whole query to an empty set.
Maybe you're looking for UNION functionality? This actually came out in 2.0.
change your 2nd MATCH to OPTIONAL MATCH, so:
START cat=node(21)
MATCH (cat)-[:HAS_KEYWORD]->(word)-[:FOUND_IN]->(doc)
OPTIONAL MATCH (cat)-[:HAS_KEYWORD]->(composit)-[:COMPOSITE_OF]->(xx)-[:FOUND_IN]->(single)
RETURN doc,single
Your OPTIONAL MATCH clause executes for everything found in your MATCH clause, but without reducing the recordset when no results are found.
http://docs.neo4j.org/chunked/stable/query-optional-match.html
Related
How does the where condition in neo4j works ?
I have simple data set with following relationship =>
Client -[CONTAINS {created:"yesterday or today"}]-> Transaction -[INCLUDES]-> Item
I would like to filter above to get the items for a transaction which were created yesterday, and I use the following query -
Match
(c:Client) -[r:CONTAINS]-> (t:Transaction),
(t) -[:INCLUDES]-> (i:Item)
where r.created="yesterday"
return c,t,i
But it still returns the dataset without filtering. What is wrong ? And how does the filtering works in neo4j for multiple MATCH statements say when I want to run my query on filetered dataset from previous steps?
Thank you very much in advance.
Your query seems fine to me. However, there are 2 things I would like to point out here:
In this case, the WHERE clause can be removed and use match by property instead.
The MATCH clause can be combined.
So, the query would be:
MATCH (c:Client) -[r:CONTAINS {created: "yesterday"}]-> (t:Transaction) -[:INCLUDES]-> (i:Item)
RETURN c, t, i
Regarding your second question, when you want to run another query on the filtered dataset from the previous step, use WITH command. Instead of returning the result, WITH will pipe your result to the next query.
For example, with your query, we can do something like this to order the result by client name and return only the client:
MATCH (c:Client) -[r:CONTAINS {created: "yesterday"}]-> (t:Transaction) -[:INCLUDES]-> (i:Item)
WITH c, t, i
ODERBY c.name DESC
RETURN c
There does not seem to be anything wrong with the cypher statement.
Applying subsequent MATCH statements can be done with the WITH clause, it's well documented here : https://neo4j.com/docs/cypher-manual/current/clauses/with/
I want a query that starting from a node, it counts the possible end nodes given relation type:
For example this query:
MATCH (start:typeA{my_id:"abc"})-[:rel]->(l:typeB) return count(l)
works great and returns a proper number, i.e., 500. The same happens with:
MATCH p=(start:BusStop{StopCode:"0247"})-[:CAN_BOARD]->(:Leg) return count(p)
However if I do:
MATCH (start:typeA{my_id:"abc"}) return count((start)-[:rel]->(:typeB))
returns 1.
What is the difference between this query and the previous ones?
The result of a path expression (as used in your last query) is a list of paths. This is different than the result when the same path pattern is used in a MATCH clause.
You would have gotten 500 if you changed your last query to use SIZE() instead of COUNT():
MATCH (start:typeA{my_id:"abc"}) return SIZE((start)-[:rel]->(:typeB))
I have a following query (first one simplified to show the issue)
OPTIONAL MATCH (recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer)-[:Reference{Id:'F09'}]-(recIncidents_F08_F09:RecordIncidents),
(recEmployee:RecordEmployee),
(recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer)
WHERE ( recIncidents_F08_F09.F01="Trojan" )
RETURN recEmployee
it doesn't return anything.
if I remove third optional match, then it works fine. Is it a bug? I was thinking means just that optional.
OPTIONAL MATCH (recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer)-[:Reference{Id:'F09'}]-(recIncidents_F08_F09:RecordIncidents),
(recEmployee:RecordEmployee)
WHERE ( recIncidents_F08_F09.F01="Trojan" )
RETURN recEmployee
Ok, I didn't want to confuse the issue, but of course people start to talk about duplicate path and what not. I thought the fact that optional matches don't return anything is a bug and maybe somebody has workaround. Here is a full query that returns nothing when it should return 2 nodes.
OPTIONAL MATCH (recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer)-[:Reference{Id:'F09'}]-(recIncidents_F08_F09:RecordIncidents),
(recEmployee:RecordEmployee),
(recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer)
WHERE ( recIncidents_F08_F09.F01="Trojan" ) OR (recComputer_F08.F02="WSMYSTATION")
RETURN recEmployee
[EDITED]
This is not a bug. The behavior results from 2 factors:
A single MATCH or OPTIONAL MATCH clause will filter out duplicate relationships, and
Your OPTIONAL MATCH has multiple patterns that contain the same exact sub-pattern involving a relationship between 2 specific nodes.
The sub-pattern (recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer) is repeated in 2 patterns within a single OPTIONAL MATCH. Since any Reference relationship found by the first instance of the pattern will also be found by the second instance, neo4j will filter out all result rows. This is why your first query gets no results.
You need to avoid repeating the same sub-pattern (involving the same relationship type between the same 2 nodes) within multiple patterns in the same MATCH or OPTIONAL MATCH clause.
The right way to write the optional query (the second one)
OPTIONAL MATCH (recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer)-[:Reference{Id:'F09'}]-(recIncidents_F08_F09:RecordIncidents)
WHERE ( recIncidents_F08_F09.F01="Trojan" )
RETURN recEmployee
union
OPTIONAL MATCH (recEmployee:RecordEmployee)-[:Reference{Id:'F08'}]-(recComputer_F08:RecordComputer)
WHERE (recComputer_F08.F02="WS-MRSPFRY02")
Unfortunately different paths with OR only possible with union after long research.
I'd like to pull and combine data from several different paths that share a path at the beginning, not all of which might exist. For example, I'd like to do something like this:
MATCH (:Complex)-[:PATH]->(s:Somewhere)-[:FETCHING]->(data)
RETURN data.attribute
UNION ALL
MATCH (s)-[:OPTIONAL]->(o:OtherData)
RETURN o.attribute;
so that it doesn't retrace the path up to s. I can't actually do this, though, because UNION separates queries and the (s)-[:OPTIONAL] in the second part will match anything with an outgoing OPTIONAL relation; the s is a loose handle.
Is there a better way of doing this than repeating the path:
MATCH (:Complex)-[:PATH]->(s:Somewhere)-[:FETCHING]->(data)
RETURN data.attribute
UNION ALL
MATCH (:Complex)-[:PATH]->(s:Somewhere)-[:OPTIONAL]->(o:OtherData)
RETURN o.attribute;
I made a few attempts using WITH, but they all either caused the query to return nothing if any part failed, or I could not get them to line up into a single column and instead got rows with redundant data, or (with multiple, nested WITHs, which I'm not sure about the scoping of) just fetching everything.
Have you looked at the semantics of an optional match? So you can match to s, beyond s and your optional component. Something like:
MATCH (:Complex)-[:PATH]->(s:Somewhere)
MATCH (s)-[:FETCHING]->(data)
OPTIONAL MATCH (s)-[:OPTIONAL]->(otherData)
RETURN data.attribute, otherData.attribute
Sorry I missed the importance of a single column, is it really important?
You can gather the vaues into a single collection :
MATCH (:Complex)-[:PATH]->(s:Somewhere)
MATCH (s)-[:FETCHING]->(data)
OPTIONAL MATCH (s)-[:OPTIONAL]->(otherData)
RETURN [data.attribute] + COLLECT(otherData.attribute)
But doesn't this work for a single column:
MATCH (:Complex)-[:PATH]->(s:Somewhere)
MATCH (s)-[:FETCHING]->(data)
OPTIONAL MATCH (s)-[:OPTIONAL]->(otherData)
WITH [data.attribute] + COLLECT(otherData.attribute) as col
RETURN UNWIND col AS val
The query as followings and get empty result. When I remove person-[:TEACH]-lesson, it works fine. Anybody can tell me what is the reason? Cheers
start person=node(1)
match person-[:TEACH|LEARN]-lesson,
person-[:TEACH]-lesson
return person,lesson
You probably don't have a TEACH relation between person and lesson.
match person-[:TEACH|LEARN]-lesson,
person-[:TEACH]-lesson
is match person-[:TEACH|LEARN]-lesson AND match person[:TEACH]-lesson, which is a repetition anyway.
start person=node(1)
match person-[:TEACH|LEARN]-lesson
return person,lesson
will work if you want to match TEACH or LEARN (as long as at least one of them exists, you'll get a result).