How to match nodes with exactly matching properties in Cypher? - neo4j

In Cypher is there a way to match nodes exactly, i.e. match where the existing node contains only the properties queried for?
For example if we have the following nodes:
CREATE (n {field1: 'value1'})
CREATE (n {field1: 'value1', field2: 'value2'})
And match:
MATCH (n {field1: 'value1'}) RETURN (n)
This will return the both nodes. However, I want the second node to be excluded because it also contains field2 which is not in the set of queried properties

One way to do this is to use the properties function, i.e.
MATCH (n) WHERE properties(n) = {field1: 'value1'} RETURN (n)
But would be good to know whether there are other/better ways

Related

Get the nodes with specific labels in neo4j

I want to get all the nodes that have specific labels. My code:
match (n) where labels(n)=["Person","Actor","Old"] return n
While there are nodes that satisfy this property I do not get any results.
This is why:
Labels(n) returns an array of strings, but not necessarily in a specific order.
You can try this:
WHERE n:Person AND n:Actor AND n:Old
Or
WHERE ALL(l in [“Person”, “Actor”, “Old”] WHERE l IN labels(n) )
List does not match if the items are not in the same order/sequence. So first of all, list out all labels in your database so you can see how the labels are arranged.
match (n)
return distinct labels(n)
Then you will see which node will have those labels that you look for: ["Person","Actor","Old"].
If you are trying to find nodes where it contains all nodes in that list in any order then this query will work for you.
match (n)
where all(lbl in ["Person","Actor","Old"] where lbl in labels(n))
return n
if you like using APOC functions, here is the query
match (n)
where apoc.coll.isEqualCollection(["Person","Actor","Old"], labels(n))
return n

How Many Nodes Are Involved in a Match

How can I know how many nodes and edges are involved in a MATCH? Is there another way besides Explain / Profile Match?
If you mean how many nodes are matched in a path, such as a variable-length path, then you can assign a path variable for this:
MATCH p = (k:Person {name:'Keanu Reeves'})-[*..8]-(t:Person {name:'Tom Hanks'})
WITH p LIMIT 1
RETURN p, length(p) as pathLength, length(p) + 1 as numberOfNodesInPath
You can also use nodes(p) and relationships(p) to get the collection of nodes and relationships that make up the path, and you can use size() on those collections to get their size.
There exists the COUNT() function of Cypher that allows you to count the number of elements. As for example in this query:
MATCH (n)
RETURN COUNT(n);
This query will count all nodes in your database.
You can find more information in the cypher manual, under the aggregating functions. Check it out.
The following Cypher snippet should return the number of distinct nodes and relationships found by any given MATCH clause. Just replace <your code here> with your MATCH pattern.
MATCH <your code here>
WITH COLLECT(NODES(p)) AS ns, SUM(SIZE(RELATIONSHIPS(p))) AS relCount
UNWIND ns AS nodeList
UNWIND nodeList AS node
RETURN COUNT(DISTINCT node) AS nodeCount, relCount;

cypher NOT IN query with Optional Match

NOT RELEVANT - SKIP TO Important Edit.
I have the following query:
MATCH (n)
WHERE (n:person) AND n.id in ['af97ab48544b'] // id is our system identifier
OPTIONAL MATCH (n)-[r:friend|connected|owner]-(m)
WHERE (m:person OR m:dog OR m:cat)
RETURN n,r,m
This query returns all the persons, dogs and cats that have a relationship with a specific person. I would like to turn it over to receive all the nodes & relationships that NOT includes in this query results.
If it was SQL it would be
select * from graph where id NOT IN (my_query)
I think that the OPTIONAL MATCH is the problematic part. I How can I do it?
Any advice?
Thanks.
-- Important Edit --
Hey guys, sorry for changing my question but my requirements has been changed. I need to get the entire graph (all nodes and relationships) connected and disconnected except specific nodes by ids. The following query is working but only for single id, in case of more ids it isn't working.
MATCH (n) WHERE (n:person)
OPTIONAL MATCH (n)-[r:friend|connected|owner]-(m) WHERE (m:person OR m:dog OR m:cat)
WITH n,r,m
MATCH (excludeNode) WHERE excludeNode.id IN ['af97ab48544b']
WITH n,r,m,excludeNode WHERE NOT n.id = excludeNode.id AND (NOT m.id = excludeNode.id OR m is null)
RETURN n,m,r
Alternatively I tried simpler query:
MATCH (n) WHERE (n:person) AND NOT n.id IN ['af97ab48544b'] return n
But this one does not returns the relationships (remember I need disconnected nodes also).
How can I get the entire graph exclude specific nodes? That includes nodes and relationships, connected nodes and disconnected as well.
try this:
match (n) where not n.id = 'id to remove' optional match (n)-[r]-(m)
where not n.id in ['id to remove'] and not m.id in ['id to remove']
return n,r,m
You've gotta switch the 'perspective' of your query... start by looping over every node, then prune the ones that connect to your person.
MATCH (bad:person) WHERE bad.id IN ['af97ab48544b']
WITH COLLECT(bad) AS bads
MATCH path = (n:person) - [r:friend|:connected|:owner] -> (m)
WHERE n._id = '' AND (m:person OR m:cat OR m:dog) AND NOT ANY(bad IN bads WHERE bad IN NODES(path))
RETURN path
That said, this is a problem much more suited to SQL than to a graph. Any time you have to loop over every node with a label, you're in relational territory, the graph will be less efficient.

Get node by property value neo4j

How can i get node by propery value? I mean something like that:
I'll tried
match (n) where has (n.name = 'Mark')
return n
But it's incorrect.
And also How can i find node with max property value. I have nodes with property "VIEWS" and i want see node with max views.
So close...
MATCH (n)
WHERE n.name = 'Mark'
RETURN n
It is better to include a node label if you have one that will serve to segregate your node from other nodes of different types. This way if you have an index on the name property and label combination you will get better search responsiveness. For instance, you can create the index...
CREATE INDEX ON :Person(name)
And then query with the Person label.
MATCH (n:Person)
WHERE n.name = 'Mark'
RETURN n
Or alternatively you can query this way...
MATCH (n:Person {name:'Mark'})
RETURN n
To find the person with the most views...
MATCH (n:Person)
RETURN n, n.views
ORDER BY n.views desc
LIMIT 1
To find the most views without the person...
MATCH (n:Person)
RETURN max(n.views)

Cypher Optional Match

I have a graph in that contains two types of nodes (objects and pieces) and two types of links (similarTo and contains). Some pieces are made of the pieces.
I would like to extract the path to each piece starting from a set of objects.
MATCH (o:Object)
WITH o
OPTIONAL MATCH path = (p:Piece) <-[:contains*]- (o) -[:similarTo]- (:Object)
RETURN path
The above query only returns part of the pieces. In the returned graph, some objects do not directly connect to any pieces, the latter are not returned, although they actually do!
I can change the query to:
MATCH (o:Object) -[:contains*]-> (p:Piece)
OPTIONAL MATCH (o) –[:similarTo]- (:Object)
However, I did not manage to return the whole path for that query, which I need to return collection of nodes and links with:
WITH rels(path) as relations , nodes(path) as nodes
UNWIND relations as r unwind nodes as n
RETURN {nodes: collect(distinct n), links: collect(distinct {source: id(startNode(r)), target: id(endNode(r))})}
I'd be grateful to any recommendation.
Would something like this do the trick ?
I created a small graph representing objects and pieces here : http://console.neo4j.org/r/abztz4
Execute distinct queries with UNION ALL
Here you'll combine the two use cases in one set of paths :
MATCH (o:Object)
WITH o
OPTIONAL MATCH p=(o)-[:CONTAINS]->(piece)
RETURN p
UNION ALL
MATCH (o:Object)
WITH o
OPTIONAL MATCH p=(o)-[:SIMILAR_TO]-()-[:CONTAINS]->(piece)
RETURN p

Resources