I'd like to know if it's possible to update a list property of a node or edge by index.
MATCH (t1:t)-[r1:o]->(a:a)<-[r2:o]-(t2:t) where r1.loc-r2.loc=-1 and r1.month=r2.month
WITH t1,t2,count(t1) as c
MERGE (t1)-[r:r]->(t2)
ON CREATE SET r.weights = "empty array of size 12(months) with array[month]=c
ON MATCH SET r.weights[month] = r.weights[month]+c
I suppose one can achieve setting the empty array with something similar to:
ON CREATE SET r.weights = reduce(a=[], i in range(0,month-1) | a + [0])+[c]+reduce(a=[], i in range(0,12-month) | a + [0])
But what's the best way to update the list property?
Thanks!
I managed to solve it in the following way:
MATCH (t1:t)-[r1:o]->(a1:a)<-[r2:o]-(t2:t) where r1.loc-r2.loc=-1 and r1.month=r2.month
WITH t1,r1,t2,r2,count(t1) as c
MERGE (t1)-[r:r]->(t2)
ON CREATE SET r.weights = reduce(a=[], i in range(0,r1.month-2) | a + [0])+[c]+reduce(a=[], i in range(0,11-r1.month) | a + [0])
ON MATCH SET r.weights = reduce(a=[], e in r.weights[0..r1.month-1]+[r.weights[r1.month-1]+c]+r.weights[r1.month..13] |a+e)
return t1,t2,c,r
Related
I'm trying to get Total(Sum) of a property of "df" object.I have attached screen shot of sample database I'm using
I tried to get the graph using following query
MATCH P= (n:Org)-[:O_CH*0..]->()-[:LEAF*0..]->()-[:CH*0..]->()-[:FOR*0..]->() RETURN P
To create objects
create(n:Org{name:'Root',id:1})
create(n:Org{name:'L1.1',id:2,parent:1})
create(n:Org{name:'L1.2',id:3,parent:1})
create(n:Org{name:'L1.3',id:4,parent:1})
create(n:Org{name:'L2.1',id:5,parent:3})
create(n:Org{name:'L2.2',id:6,parent:4})
create(n:Op{name:'CH1',id:7,orgId:5})
create(n:Op{name:'CH2',id:8,orgId:5 ,parent:'CH1'})
create(n:Proj{name:'P1',id:9,opp:'CH2'})
create(n:Proj{name:'P2',id:10,opp:'CH1'})
create(n:R{name:'R1',id:200,orgId:2 })
create (n:df{id:100,map:8,forecast:toFloat(10)})
create (n:df{id:101,map:7,forecast:toFloat(10)})
create (n:df{id:102,map:9,forecast:toFloat(10)})
create (n:df{id:103,map:10,forecast:toFloat(10)})
create (n:df{id:104,map:200,forecast:toFloat(10)})
To Crate relationships
MATCH (c:Org),(p:Org) WHERE c.parent = p.id create (p)-[:O_CH]->(c)
MATCH (c:Op),(p:Op) WHERE c.parent = p.name create (p)-[:CH]->(c)
MATCH (c:Op),(p:Org) WHERE c.orgId = p.id create (p)-[:LEAF]->(c)
MATCH (c:Proj),(p:Op) WHERE c.opp = p.name create (p)-[:CH]->(c)
MATCH (c:R),(p:Org) WHERE c.orgId = p.id create (p)-[:LEAF]->(c)
MATCH (c:df),(p:) WHERE c.map = p.id create (p)-[:FOR]->(c)
I'm expecting 60 as total where I get 260 as total. Please let me know where I'm wrong . Need your help to figure out.
I'm trying to get Total(Sum) of a property of "df" object.
I believe you needs a simple query that match all nodes with label :df and return the sum of node.forecast. Try it:
// Match all nodes with :df label
MATCH(n:df)
// Return the sum of the property 'forecast' of each matched node
RETURN sum(n.forecast)
From comments:
Thank you Bruno.But the thing i need to get the aggregated value as a
example if i select L2.1 , i need to get the sum of df objects which
are under that node
This should work:
MATCH({name:'L2.1'})-[*]->(n)
RETURN SUM(n.forecast)
I have 2 csv files and their sructure is as follows:
1.csv
id name age
1 aa 23
2 bb 24
2.csv
id product location
1 apple CA
2 samsung PA
1 HTC AR
2 philips CA
3 sony AR
// 1.csv
LOAD CSV WITH HEADERS FROM "file:///G:/1.csv" AS csvLine
CREATE (a:first { id: toInt(csvLine.id), name: csvLine.name, age: csvLine.age})
// 2.csv
LOAD CSV WITH HEADERS FROM "file:///G:/2.csv" AS csvLine
CREATE (b:second { id: toInt(csvLine.id), product: csvLine.product, location: csvLine.location})
Now i want to create another node called "third", using the following cypher query.
LOAD CSV WITH HEADERS FROM "file:///G:/1.csv" AS csvLine
MATCH c = (a:first), d = (b.second)
FOREACH (n IN nodes(c) |
CREATE (e:third)
SET e.name = label(a) + label(b) + "id"
SET e.origin = label(a)
SET e.destination = label(b)
SET e.param = a.id)
But the above query give me duplicate entries. I think here it runs 2 time after the load. Please suggest or any alternative way for this.
CREATE always creates, even if something is already there. So that's why you're getting duplicates. You probably want MERGE which only creates an item if it doesn't already exist.
I wouldn't ever do CREATE (e:third) or MERGE (e:third) because without specifying properties, you'll end up with duplicates anyway. I'd change this:
CREATE (e:third)
SET e.name = label(a) + label(b) + "id"
SET e.origin = label(a)
SET e.destination = label(b)
SET e.param = a.id)
To this:
MERGE (e:third { name: label(a) + label(b) + "id",
origin: label(a),
destination: label(b),
param: a.id })
This then would create the same node when necessary, but avoid creating duplicates with all the same property values.
Here's the documentation on MERGE
You don't use csvLine at all for matching the :first and :second node!
So your query doesn't make sense
This doesn't make sense either:
MATCH c = (a:first), d = (b.second)
FOREACH (n IN nodes(c) |
CREATE (e:third)
c are paths with a single node, i.e. (a)
so instead of the foreach you would use a directly instead
I want to add a value to an array if its not already there.
So far my code looks something like this (note that both r.names and {name} are arrays, and [1] + [2] = [1,2]):
MERGE (r:resource {hash:{hash}})
ON CREATE SET r.names = {name}
ON MATCH SET r.names = r.names + {name}
but obviously if {name} is already in r.names, it just gets added again. How can I add {name} only if r.names doesn't already contain it?
I guess you need to use the FOREACH + CASE WHEN trick: using a case when you use either a 1 element array (if your condition is true) or a 0 element array otherwise as iterator used in FOREACH. FOREACH cannot be used in a ON MATCH or ON CREATE handler, so we put it after the MERGE and use a coalesce to cover the case when r.names does not yet exist:
MERGE (r:Resource {hash:{hash}})
FOREACH(x in CASE WHEN {name} in r.names THEN [] ELSE [1] END |
SET r.names = coalesce(r.names,[]) + {name}
)
RETURN r.names
Use FILTER to get an array of the elements that aren't already in r.names and add them:
MERGE (r:resource {hash:{hash}})
ON CREATE SET r.names = {new_names}
ON MATCH SET r.names = r.names + FILTER(
el FOR el in {new_names} IF NOT el IN r.names
)
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.
I have a set of nodes with a property, myproperty = "James" I want to update that property from (myproperty) to (name).
Is there any way to this with Cypher?
Solved by myself, heres what I did:
MATCH (n:term)
SET n.name = n.label
REMOVE n.label
RETURN n
You can change your old column name by using following query
MATCH (n:term)
SET n.name = n.myproperty
REMOVE n.myproperty
RETURN n
match (a:employee {employeeId:123,location:1})
set a.newProperty=a.oldProperty
remove a.oldProperty
return a;