Neo4j: Conditional return/IF clause/String manipulation - neo4j

This is in continuation of Neo4j: Listing node labels
I am constructing a dynamic MATCH statement to return the hierarchy structure & use the output as a Neo4j JDBC input to query the data from a java method:
MATCH p=(:Service)<-[*]-(:Anomaly)
WITH head(nodes(p)) AS Service, p, count(p) AS cnt
RETURN DISTINCT Service.company_id, Service.company_site_id,
"MATCH srvhier=(" +
reduce(labels = "", n IN nodes(p) | labels + labels(n)[0] +
"<-[:BELONGS_TO]-") + ") WHERE Service.company_id = {1} AND
Service.company_site_id = {2} AND Anomaly.name={3} RETURN " +
reduce(labels = "", n IN nodes(p) | labels + labels(n)[0] + ".name,");
The output is as follows:
MATCH srvhier=(Service<-[:BELONGS_TO]-Category<-[:BELONGS_TO]-SubService<-
[:BELONGS_TO]-Assets<-[:BELONGS_TO]-Anomaly<-[:BELONGS_TO]-) WHERE
Service.company_id = {1} and Service.company_site_id = {21} and
Anomaly.name={3} RETURN Service.name, Category.name, SubService.name,
Assets.name, Anomaly.name,
The problem I am seeing:
The "BELONGS_TO" gets appended to my last node
Line 2: Assets<-[:BELONGS_TO]-Anomaly**<-[:BELONGS_TO]-**
Are there string functions (I have looked at Substring..) that can be used to remove it? Or can I use a CASE statement with condition n=cnt to append "BELONGS_TO"?
The same problem persists with my last line:
Line 5: Assets.name,Anomaly.name**,** - the additional "," that I need to eliminate.
Thanks.

I think you need to introduce a case statement into the reduce clause something like this snippet below. If the node isn't the last element of the collection then append the "<-[:BELONGS_TO]-" relationship. If it is the last element then don't append it.
...
reduce(labels = "", n IN nodes(p) |
CASE
WHEN n <> nodes(p)[length(nodes(p))-1] THEN
labels + labels(n)[0] + "<-[:BELONGS_TO]-"
ELSE
labels + labels(n)[0]
END
...

Cypher has a substring function that works basically like you'd expect. An example: here's how you'd return everything but the last three characters of a string:
return substring("hello", 0, length("hello")-3);
(That returns "he")
So you could use substring to trim the last separator off of your query that you don't want.
But I don't understand why you're building your query in such a complex way; you're using cypher to write cypher (which is OK) but (and I don't understand your data model 100%) it seems to me like there's probably an easier way to write this query.

Related

Logical grouping of operator with Neo4jClient

I cant seem to figure out how to write this query using the Neo4jClient
MATCH (n)
WHERE (n.Id="1ef17d65-492e-4c0d-aa79-13065edd37f2" AND n.CaseType="NaturalPerson") OR (n.Id="a5c143d4-0306-4057-a96f-e39c5c50eb22" AND n.CaseType="NaturalPerson")
RETURN n
If i write the query like this
this.client.Cypher.Match("(n)")
.Where("f.Id=\"1ef17d65-492e-4c0d-aa79-13065edd37f2\"")
.AndWhere("n.CaseType=\"NaturalPerson\"")
.OrWhere("f.Id=\"1ef17d65-492e-4c0d-aa79-13065edd37f2\"")
.AndWhere("n.CaseType=\"NaturalPerson\"")
.Return((n, r) => n.As<T>());
The following query is generated, but it does not have the parentheses '(' ')' which logicly group the two and clauses
MATCH (n)
WHERE f.Id="1ef17d65-492e-4c0d-aa79-13065edd37f2"
AND n.CaseType="NaturalPerson"
OR f.Id="1ef17d65-492e-4c0d-aa79-13065edd37f2"
AND n.CaseType="NaturalPerson"
RETURN n AS Node, r AS Metadata
You either do:
.Where("n.Id='1ef17d65-492e-4c0d-aa79-13065edd37f2' AND n.CaseType='NaturalPerson')
.OrWhere("n.Id='a5c143d4-0306-4057-a96f-e39c5c50eb22' AND n.CaseType='NaturalPerson'")
or, you could put it all in one .Where
But, if it was me, I would do:
.Where("n.CaseType = 'NaturalPerson')
.AndWhere("n.Id IN ['1ef17d65-492e-4c0d-aa79-13065edd37f2','a5c143d4-0306-4057-a96f-e39c5c50eb22']
And I would definitely be using parameters like so:
var ids = new [] {'a5c143d4-0306-4057-a96f-e39c5c50eb22', '1ef17d65-492e-4c0d-aa79-13065edd37f2'};
var caseType = "NaturalPerson";
this.client.Cypher.Match("(n)")
.Where("n.CaseType = $caseTypeParam")
.AndWhere("n.Id IN $idsParam")
.WithParam("caseTypeParam", caseType)
.WithParam("idsParam", ids")
/*.. etc..*/

Neo4j cypher return Path with a specific format

I have a cypher query to return the shortest Path between two nodes.
I am using Java JdbcTemplate.
MATCH (nodeA),(nodeB), p = shortestPath((nodeA)-[*..15]-(nodeB)) " //
+ "WHERE ID(nodeA) = {1} and ID(nodeB) = {2} RETURN nodes(p) as nodes " //
+ ",relationships(p) as edges
My problem is that I have a Util method that do the mapping of the jdbctempate result. It only works when my cypher returns nodes suchs as :
RETURN { id : id(node), labels : labels(node), data: node } as node
Is there a way to make my initial cypher return the result in that format?
NODES returns a list of nodes, so you can use UNWIND to unpack the list into a set of rows. So in your example...
MATCH (nodeA),(nodeB), p = shortestPath((nodeA)-[*..15]-(nodeB))
WHERE ID(nodeA) = {1} AND ID(nodeB) = {2}
UNWIND nodes(p) as n
RETURN { id : id(n), labels : labels(n), data: n} as node, relationships(p) as edges
You can use WITH + COLLECT to fold the nodes back into a list, and then perform the same operation on relationships if you need.

Getting alphanumeric reference of nodes in py2neo, when looking for paths

I have a graph that consists of DATASET and GRAPH nodes. With the following relationships:
DATASET->READS->GRAPH
GRAPH->WRITES->DATASET
When I run the following : MATCH (p1:DATASET_NAME { name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3))
RETURN p
In Neo4J Desktop I get a result that is correct, where node names are present. But when I run it in py2neo:
graph.run("MATCH (p1:DATASET_NAME {
name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3)) RETURN p").dump()
I get a result in the following format:
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(f9ddd22)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(f9ddd22)-[:READS]->(fcca016)-[:WRITES]->(e152f69)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(cbc5d42)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
I am assuming that these are some sort of references. Is there a way where I can get the string value for name from these references?
You are returning the matched path so what you see in py2neo is the representation of the path object. In the neo4j console it does a little extra looking up for you and presents the path as a set of nodes and relationships and it labels them according to what you have configured in the console.
If you want to see the names in your py2neo output you could use the reduce function on the returned path p to produce a string with the node names and relationship types. Something like this should get you started.
MATCH (p1:DATASET_NAME { name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3))
RETURN head(nodes(p)).name + ' - ' + reduce(path_str = "", r in relationships(p) | path_str + type(r) + ' - ' + endnode(r).name)
In py2neo [Note the escape characters added in order to avoid cypher error. # ...reduce(path_str = \"\"... ]:
graph.run("MATCH (p1:DATASET_NAME { name:'/projects/bkrpty_vfcn/bkrpty_vfcn_vendr/data/serial/temp/yyyymmdd_yyyymmddhhmiss_bk_mrk_stat_init.dat' }),(p3:DATASET_NAME { name:'/projects/bkrpty_vfcn/bkrpty_vfcn_vendr/tables/onevgb1/ai_bkrpty_case' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3)) RETURN head(nodes(p)).name + ' - ' + reduce(path_str = \"\", r in relationships(p) | path_str + type(r) + ' - ' + endnode(r).name)").dump()

neo4j cypher left padding String in Where Clause

I have a String property in my nodes where the length of the String isn't fix.
Now i must search the right node by this property but i get a fixed length value from another System. For Example my Node has the Value '0123' but I get the Information '000123' for searching.
I need a function like left padding with Zeros and this in the Where Clause like
MATCH (a:LABEL) where leftPad(a.property, 6, '0') = '000123' return a
LIMIT 1
Is something like this possible with a good Performance?
You could do this:
MATCH (a:LABEL)
WHERE SUBSTRING('00000', 0, SIZE(a.property)) + a.property = '000123'
RETURN a
LIMIT 1;
Or, if all the characters are numeric, then you could do this:
MATCH (a:LABEL)
WHERE TOINT(a.property) = TOINT('000123')
RETURN a
LIMIT 1;
However, it would be even better if you could just store the property value as an integer in the first place, and also compare it to an integer, which would be the fastest. This might be very easy to do, depending on your situation.
MATCH (a:LABEL)
WHERE a.property = 000123
RETURN a
LIMIT 1;
Try it with reduce:
MATCH (a:LABEL)
WHERE REDUCE(lp='', n in RANGE(0,5-size(a.name)) | lp+'0')+a. a.property = '000123'
RETURN a
or try it with regular expression:
MATCH (a:LABEL)
WHERE a.property =~ '(0){0,3}123'
RETURN a

How do I get list of nodes from calculated shortest path?

My Cypher looks like this:
START source=node(16822), target=node(12449)
MATCH p = allShortestPaths(source-[*]-target)
return p
And I want to write equivalent C# code for this. This is what I've come up till now
var query = client.Cypher
.Start(new { source = sourceNode.Reference, target = targetNode.Reference })
.Match("p = allShortestPaths(source-[*]-target)")
.Return<Node<Data>>("x");
Where Data is the class which has a string property(string ID).
What should i put in place of x to get my result as a list of concatenated IDs which comprises the path.
Cypher 2.0
START source=node(16822), target=node(12449)
MATCH p = allShortestPaths(source-[*]-target)
return nodes(p)
Good old way of executing query was the last resort which i used
CypherQuery query1 = new CypherQuery(#"START m=node(" + sourceNode.Reference.Id.ToString() + "), n=node(" + targetNode.Reference.Id.ToString() + #")
match p = allshortestpaths(m-[*]-n)
return distinct Extract(x in NODES(p): x.NodeId) as paths", paramCollection, CypherResultMode.Set);
var paths = ((IRawGraphClient)client).ExecuteGetCypherResults<List<string>>(query1);

Resources