Neo4j Cypher match doesn't find node that it should - neo4j

Having added nodes with properties "id" and "name"
CREATE (s:subsystem {id: 12, name:"InjectEolCurrentCellSOCs"})
CREATE (s:subsystem {id: 13, name:"InjectEolCellCapacities"})
CREATE (s:subsystem {id: 14, name:"InjectEolCellResistances"})
CREATE (s:subsystem {id: 15, name:"InjectEolCellSOCs"})
This command works/finds the node and returns the requested value:
match(n {id:13}) return (n.name);
But this command does not find a match:
match(n {name:"InjectEolCellCapacities"}) return (n);
Could this be related to the fact that "InjectEolCellCapacities" and "InjectEolCellResistances" have the same first 13 characters ?

If you look at your first imag, you will see that you have saved the data "InjectEolCellCapacities " (there is a space at the end).
So if you want to match it, yu should use this query : MATCH (n:subsystem { name:"InjectEolCellCapacities "}) RETURN n
You can also search all subsystem node that have a name property that starts with InjectEolCellCapacities like this : MATCH (n:subsystem) WHERE n.name STARTS WITH 'InjectEolCellCapacities' RETURN n

Related

Neo4j (4.1.3) : How to create relationship on the fly when match returns exactly one row for one label

I am using neo4j 4.1.3. I have 2 labels : Person and Rec. I need to create a relationship between these 2 only when there exists exactly one person with that last name. When I run the below, relationships are created for all persons with that last name. My code is below:
MATCH (echk:REC {id: 'abcdef'})
OPTIONAL MATCH (p:Person) WHERE p.name CONTAINS 'Shirley'
WITH p, echk, count(p) as personcnt
where personcnt=1
CALL apoc.merge.relationship(p, 'Test', {}, {}, echk, {}) YIELD rel
RETURN p, echk, rel
I have 33 people with "Shirley' and 33 relationships are getting created with that REC. However, there should be no relationship.
Run this
MATCH (echk:REC {id: 'abcdef'})
OPTIONAL MATCH (p:Person) WHERE p.name CONTAINS 'Shirley'
RETURN p, echk, count(p) as personcnt
and you'll see why all 33 are created.
If there can only be one match, I suggest trying to find the "one" Shirley first, if they don't exist you are done, if more than one you are done. If and only if only one match returns, then continue on to match with 'abcdef' and do the merge.
If I have both p and count(p) in the WITH, I always get 1 for count(p) which makes sense. So I have changed my query as below to make this to work:
OPTIONAL MATCH (p:Person) WHERE p.name CONTAINS 'Shirley'
WITH count(p) AS cnt WHERE cnt = 1
MATCH (echk:REC {id: 'abcdef'})
MATCH (p:Person) where p.name contains 'Shirley'
CALL apoc.merge.relationship(p, 'Test', {}, {}, echk, {}) yield rel
I have now added this to my cypher logic to create dynamic relationship and it works as expected. Hopefully this helps someone at a later date.

Accessing nodes in path in neo4j without apoc

Can anyone tell me if this is possible? When trying to use
Unwind apoc.coll.pairsMin(nodes(p)) as pair
It throws
Neo.ClientError.Statement.SyntaxError: Unknown function 'apoc.coll.pairsMin' (line 3, column 8 (offset: 99))
"Unwind apoc.coll.pairsMin(nodes(p)) as pair"
If possible I would prefer to find a solution using out of the box software
[UPDATED]
This snippet should work:
WITH NODES(p) AS ns
UNWIND [i IN RANGE(0,SIZE(ns)-2) | ns[i..i+2]] AS pair
Something like this work for you?
// find the path you are interested in
MATCH p=(:Node {name: 'start'})-[*]->(:Node {name: 'end'})
// use reduce to iterate over the relationships
// accumulate the collections of the start and endNode for each relation
RETURN REDUCE (pairs = [], rel in relationships(p) | pairs + [[startNode(rel), endNode(rel)]] ) AS pairs
The equivalent APOC call would look like this
MATCH p=(:Node {name: 'start'})-[*]->(:Node {name: 'end'})
RETURN apoc.coll.pairsMin(nodes(p)) as pairs

Neo4j add/update property ONLY if node exists. If not then do nothing

It's extiension of question Neo4j Add/update properties if node exists
There's answer how to MERGE (create or update) node:
You could set them all at once with a map for all attributes
merge (n:Node {name: 'John'})
set n = {name: 'John', age: 34, coat: 'Yellow', hair: 'Brown'}
return n
If you just wanted to replace the attributes age and coat, you could do this instead.
merge (n:Node {name: 'John'})
set n.age = 34, n.coat = 'Yellow'
return n
Or you could add it as a map too
merge (n:Node {name: 'John'})
set n += {age: 34, coat: 'Yellow'}
return n
Can anyone tell how to UPDATE node ONLY if it exists, but do nothing if node doesn't exists.
The simplest way is
MATCH (n{id:{uuid}) SET n.prop=true
If the match fails, their will be nothing to do the SET against.
Assuming that you would like to still have rows after; (so you can still also return data for a more complex query) You can just make the match optional
...
OPTIONAL MATCH (n{id:{uuid}) SET n.prop=true
Again, if the match fails, n will be null, and the SET will do nothing

Neo4j Passing distinct nodes through WITH in Cypher

I have the following query, where there are 3 MATCHES, connected with WITH, searching through 3 paths.
MATCH (:File {name: 'A'})-[:FILE_OF]->(:Fun {name: 'B'})-->(ent:CFGEntry)-[:Flows*]->()-->(expr:CallExpr {name: 'C'})-->()-[:IS_PARENT]->(Callee {name: 'd'})
WITH expr, ent
MATCH (expr)-->(:Arg {chNum: '1'})-->(id:Id)
WITH id, ent
MATCH (entry)-[:Flows*]->(:IdDecl)-[:Def]->(sym:Sym)
WHERE id.name = sym.name
RETURN id.name
The query returns two distinct id and one distinct entry, and 7 distinct sym.
The problem is that since in the second MATCH I pass "WITH id, entry", and two distinct id were found, two instances of entry is passed to the third match instead of 1, and the run time of the third match unnecessarily gets doubled at least.
I am wondering if anyone know how I should write this query to just make use of one single instance of entry.
Your best bet will be to aggregate id, but then you'll need to adjust your logic in the third part of your query accordingly:
MATCH (:File {name: 'A'})-[:FILE_OF]->(:Fun {name: 'B'})-->(ent:CFGEntry)-[:Flows*]->()-->(expr:CallExpr {name: 'C'})-->()-[:IS_PARENT]->(Callee {name: 'd'})
WITH expr, ent
MATCH (expr)-->(:Arg {chNum: '1'})-->(id:Id)
WITH collect(id.name) as names, ent
MATCH (entry)-[:Flows*]->(:IdDecl)-[:Def]->(sym:Sym)
WHERE sym.name in names
RETURN sym.name

How to build a correlated subquery?

I have something like:
create (:ex {name: "x", ver: 1.0});
create (:ex {name: "x", ver: 1.1});
create (:ex {name: "y", ver: 0.9});
and want to return the latest version for any given name i.e. x-1.1 and y-0.9. I've tried this:
match (n:ex), (m:ex) where m.name = n.name and m.ver = max(n.ver) return m
but neo hates me with:
Invalid use of aggregating function max(...) in this context (line 1, column (x) (offset: 61))
what's the correct approach here?
* Edit I *
I did also try stringing my versions together:
create (:ex {name: "x", ver: 1.0})-[:PrecededBy]->(:ex {name: "x", ver: 1.1});
match (n:ex {name: "x", ver: 1.1}) create (n)->[:PrecededBy]->(:ex {name: "x", ver: 1.2});
create (:ex {name: "y", ver: 0.9});
thinking I could use endNode() but that doesn't seem to work at all:
match (n:ex)-[r]-() return endNode(r)
returns 3 nodes!
* Edit II *
I might have thought something like this might have worked:
match p=(:ex)-[*]->(:ex) return last(nodes(p))
but clearly I don't understand last()
When you use aggregation functions like MAX() and COLLECT() (which are only valid in WITH and RETURN clauses), you can also specify one or more non-aggregating "grouping keys" in the same clause.
For example, to get the maximum version (max_ver) for every distinct name (the "grouping key"):
MATCH (n:ex)
RETURN n.name AS name, MAX(n.ver) AS max_ver;
[UPDATED]
On the other hand, if you want to get the node with the maximum version for each name, here is one way to do that:
MATCH (n:ex)
WITH n
ORDER BY n.ver DESC
WITH n.name AS name, COLLECT(n) AS ns
RETURN name, ns[0] AS latest;
This query orders all the nodes by descending version number, collects the nodes with the same name (maintaining the order), and returns a row with each name and the node having that name with the highest version number.

Resources