I'm using neomodel and I have the following models:
class ForumElement(StructuredNode):
uid = UniqueIdProperty()
created_at = DateTimeProperty(default=dt.datetime.utcnow())
text = StringProperty()
is_visible = BooleanProperty(default=True)
picture = Relationship(Picture, 'HAS_PICTURE')
author = Relationship(User, 'HAS_USER')
class Post(ForumElement):
title = StringProperty(default="")
latitude = FloatProperty()
longitude = FloatProperty()
tags = Relationship(Tag, 'HAS_TAGS')
class Comment(ForumElement):
parent = Relationship(ForumElement, 'HAS_PARENT')
With that code I have in the database something like the image, where in blue we have "comments" and in pink we have "post".
Now, I would like to have as result of a query a list of couple <parent.uid, childen.uid>, how could I obtain that? Notice that the parent of a Comment could be a Post or another Comment
On neo4j you can use a basic Cypher query like this:
MATCH(c)-[:HAS_PARENT]->(p)
RETURN c.uid, p.uid
Just MATCH according to the pattern of one relationship with label HAS_PARENT and RETURN only the uid properties.
When used with neomodel on python, it can be called like this:
query = '''MATCH(c)-[:HAS_PARENT]->(p) RETURN c.uid, p.uid'''})
results, meta = db.cypher_query(query, {})
You can test it on mock data like this:
MERGE (mark:COMMENT {uid: "Mark"})
MERGE (lju:COMMENT {uid: "Lju"})
MERGE (praveena:COMMENT {uid: "Praveena"})
MERGE (zhen:POST {uid: "Zhen"})
MERGE (martin:COMMENT {uid: "Martin"})
MERGE (mark)-[:HAS_PARENT]-(lju)
MERGE (lju)-[:HAS_PARENT]-(praveena)
MERGE (praveena)-[:HAS_PARENT]-(zhen)
MERGE (martin)-[:HAS_PARENT]-(zhen)
Related
How do I create and update nodes and property using plain cypher query?
Below is my query:
MERGE (c:contact {guid : '500010'})
ON CREATE SET
c.data_source = '1',
c.guid = '500010',
c.created = timestamp()
ON MATCH SET
c.lastUpdated = timestamp()
MERGE (s:speciality {specialtygroup_desc : 'cold'})
ON CREATE SET s.data_source = '1',
s.specialtygroup_desc = 'fever',
s.created = timestamp()
ON MATCH SET s.data_source = '1',
s.specialtygroup_desc = 'comman cold',
s.lastUpdated = timestamp()
MERGE (c)-[r:is_specialised_in]->(s)
ON CREATE SET
r.duration = 1
ON MATCH SET
r.duration = r.duration + 1
On the first run, node is created as "fever".
On the second run, I have updated the specialty_group to "common cold". But it is creating new node with "fever". I am not able to update the "fever" to "common cold".
What changes should I make to the above query?
The MERGE (s:speciality {specialtygroup_desc : 'cold'}) clause looks for a specialtygroup_desc value of "cold".
During the first execution, that MERGE clause finds no "cold" node -- so it creates one, and the subsequent ON CREATE clause changes it to "fever".
During the second execution, that MERGE again finds no "cold" node (since it is now a "fever" node), so it again creates a "cold" node and the ON CREATE clause yet again changes it to "fever". The ON MATCH clause is never used. This is why you end up with another "fever" node.
Unfortunately, you have not explained your use case in enough detail to offer a recommendation for how to fix your code.
I think you want to update all node "cold" to "common cold" and if not exists "cold" or "common cold", create new "fever" ?
My suggestion:
OPTIONAL MATCH (ss:speciality {specialtygroup_desc : 'cold'}
SET ss.specialtygroup_desc='common cold', ss.lastUpdated = timestamp()
MERGE (c:contact {guid : '500010'})
ON CREATE SET
c.data_source = '1',
c.guid = '500010',
c.created = timestamp()
ON MATCH SET
c.lastUpdated = timestamp()
MERGE (s:speciality {specialtygroup_desc : 'common cold'})
ON CREATE SET s.data_source = '1',
s.specialtygroup_desc = 'fever',
s.created = timestamp()
MERGE (c)-[r:is_specialised_in]->(s)
ON CREATE SET
r.duration = 1
ON MATCH SET
r.duration = r.duration + 1
I have edges like this:
(People)-[:USE]->(Product)
(People)-[:REVIEW]->(Product)
Now I have a new csv of People who are reviewers but they are missing some of the attributes I have already.
I want to do something like:
LOAD CSV WITH HEADERS FROM "file:///abcd.csv" AS row
MERGE (svc:Consumer {name: row.referring_name})
ON CREATE SET
svc.skewNum = toInteger(row.skew_num)
MERGE (p:PrimaryConsumer) WHERE p.name = svc.name
ON MATCH SET
svc.city = p.city,
svc.latitude = toFloat(p.latitude),
svc.longitude = toFloat(p.longitude),
svc.consumerId = toInteger(p.primaryConsumerId)
Which borks:
Neo.ClientError.Statement.SyntaxError: Invalid input 'H': expected 'i/I' (line 10, column 28 (offset: 346))
"MERGE (p:PrimaryConsumer) WHERE p.name = svc.name"
I am 100% assured that the names are unique and will match a unique consumer name in the existing set of nodes (to be seen).
How would I add existing attributes to new data when I have a match on unique node attributes? (I am hoping to get unique id's, but I have to be able to perform an update to the new data on match)
Thank you.
This is the entire cypher script -- modified as per #cypher's input.
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///abcde.csv" AS row
MERGE (svc:Consumer {name: row.referring_name})
ON CREATE SET
svc.skeyNum = toInteger(row.skew_num)
MATCH (p:primaryConsumer {name: svc:name})
ON MATCH SET
svc.city = p.city,
svc.latitude = toFloat(p.latitude),
svc.longitude = toFloat(p.longitude),
svc.providerId = toInteger(p.providerId)
MERGE (spec:Product {name: row.svc_prod_name})
ON CREATE SET
spec.name = row.svc_prov_name,
spec.skew = toInteger(row.skew_id),
spec.city = row.svc_prov_city,
spec.totalAllowed = toFloat(row.total_allowed)
MERGE (svc)-[r:CONFIRMED_PURCHASE]->(spec)
ON MATCH SET r.totalAllowed = r.totalAllowed + spec.totalAllowed
ON CREATE SET r.totalAllowed = spec.totalAllowed
;
MERGE does not accept a WHERE clause.
Change this:
MERGE (p:PrimaryConsumer) WHERE p.name = svc.name
to this:
MERGE (p:PrimaryConsumer {name: svc.name})
[EDIT]
You entire query should then look like this:
LOAD CSV WITH HEADERS FROM "file:///abcd.csv" AS row
MERGE (svc:Consumer {name: row.referring_name})
ON CREATE SET
svc.skewNum = toInteger(row.skew_num)
MERGE (p:PrimaryConsumer {name: svc.name})
ON MATCH SET
svc.city = p.city,
svc.latitude = toFloat(p.latitude),
svc.longitude = toFloat(p.longitude),
svc.consumerId = toInteger(p.primaryConsumerId)
I am trying to make a Cypher query which makes 2 nodes and adds a relationship between them.
For adding a node I'm checking if the node is existing or not, if existing then I'm simply going ahead and setting a property.
// Query 1 for creating or updating node 1
MERGE (Kunal:PERSON)
ON CREATE SET
Kunal.name = 'Kunal',
Kunal.type = 'Person',
Kunal.created = timestamp()
ON MATCH SET
Kunal.lastUpdated = timestamp()
RETURN Kunal
// Query 2 for creating or updating node 2
MERGE (Bangalore: LOC)
ON CREATE SET
Bangalore.name = 'Bangalore',
Bangalore.type = 'Location',
Bangalore.created = timestamp()
ON MATCH SET
Bangalore.lastUpdated = timestamp()
RETURN Bangalore
Likewise I am checking if a relationship exists between the above created nodes, if not exists then creating it else updating its properties.
// Query 3 for creating relation or updating it.
MERGE (Kunal: PERSON { name: 'Kunal', type: 'Person' })
MERGE (Bangalore: LOC { name: 'Bangalore', type: 'Location' })
MERGE (Kunal)-[r:LIVES_IN]->(Bangalore)
ON CREATE SET
r.duration = 36
ON MATCH SET
r.duration = r.duration + 1
RETURN *
The problem is these are 3 separate queries which will have 3 database calls when I run it via the Python driver. Is there a way to optimize these queries into a single query.
Of course you can concatenate your three queries to one.
In this case you can omit the first and second MERGE of your last query, because it is assured by the start of new query already.
MERGE (kunal:PERSON {name: ‘Kunal'})
ON CREATE SET
kunal.type = 'Person',
kunal.created = timestamp()
ON MATCH SET
kunal.lastUpdated = timestamp()
MERGE (bangalore:LOC {name: 'Bangalore'})
ON CREATE SET
bangalore.type = 'Location',
bangalore.created = timestamp()
ON MATCH SET
bangalore.lastUpdated = timestamp()
MERGE (kunal)-[r:LIVES_IN]->(bangalore)
ON CREATE SET
r.duration = 36
ON MATCH SET
r.duration = r.duration + 1
RETURN *
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 been trying to create nodes and relations ships for our new module with neo4jphp [https://github.com/jadell/neo4jphp/wiki].
I am using cypher queries for the same.
Creating nodes with below query:
$queryNodes = "CREATE (n:User { props } ) ";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryNodes, array('props' => $arrNodeProperties));
$result = $query->getResultSet();
Creating relationships with below query:
$queryRelations = "
MATCH (authUser: User { userid: 0001 }),(friend)
WHERE friend.userid IN ['" . implode("','",$relations) . "']
CREATE UNIQUE (authUser)-[r:KNOWS { connection: 'user_friend' }]->(friend)";
So far node creation works gr8.
But when i try to create Unique relationships for the nodes, it takes too long....
Note:
There is unique constraint userid for label User, hence node with label user is indexed by Neo4j on property userid.
CREATE CONSTRAINT ON (user:User) ASSERT user.userid IS UNIQUE
Questions:
Is there any other way we can achieve creating unique relationships.
Can i use index on relationships?? If Yes how can I achieve the same.
You might try use use MERGE instead of CREATE UNIQUE. Additionally use a Cypher parameter for the fried's list instead of concatenation on client side, see http://docs.neo4j.org/chunked/stable/cypher-parameters.html
Finally I worked it out with few changes...
Thanks #MichaelHunger for the help.
So here is how i did it...
Creating Unique Nodes using MERGE, FOREACH, ON CREATE SET and params:
$queryNodes = "
FOREACH (nodeData IN {nodeProperties}|
MERGE (n:User { userid: nodeData.userid })
ON CREATE SET
n.login = nodeData.login,
n.userid = nodeData.userid,
n.username = nodeData.username,
n.name = nodeData.name,
n.gender = nodeData.gender,
n.profile_pic = nodeData.profile_pic,
n.create_date = timestamp()
ON MATCH SET
n.update_date = timestamp()
)
";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryNodes, array('nodeProperties' => $arrNodeProperties));
$result = $query->getResultSet();
Creating Unique Relationships with below query:
$queryRelations = "
MATCH (authUser: User { userid: {authUserid} }), (friend:User)
WHERE friend.userid IN {friendUserIds}
CREATE UNIQUE (authUser)-[r:KNOWS { connection: 'user_friend' }]->(friend)
";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryRelations, array('friendUserIds' => $arrFriendUserId, 'authUserid' => $authUserid));
$result = $query->getResultSet();
Please comment if we can improve the same even further.