Create relationship with properties using a query in Cypher - neo4j

I would like to know if this is possible. I have a query that produces a nice report showing a relationship between two entities through two other nodes. There can be more than one path. I now want to create a direct relationship between those two nodes and count the number of paths and sum based upon data in the nodes in between. the report query is below.
match (bo:BuyerAgency)<-[:IS_FOR_BO]-(sol:Solicitation)-[:SELECTED]->(prop:Proposal)<-[:OWNS_BID]-(so:VendorOrg)
where sol.currStatus='Awarded'
return bo.AgencyName, count(sol.Number) as awards, so.orgName, sum(prop.finalPrice) as awardVolume;
What I want to do is similar to below which will not work.
match (bo:BuyerAgency)<-[:IS_FOR_BO]-(sol:Solicitation)-[:SELECTED]->(prop:Proposal)<-[:OWNS_BID]-(so:VendorOrg)
where sol.currStatus='Awarded'
create (bo)-[:HAS_AWARDED{awardCount: count(sol.Number), awardVolume: sum(prop.finalPrice)}]->(so);
If I remove the properties for the relationship, it works but want to add the properties without to much programing.
I am using the most recent version of Neo4j 3.2.
thanks

The problem here is you are trying to use count() and sum() functions in an invalid context. The below query should work:
match (bo:BuyerAgency)<-[:IS_FOR_BO]-(sol:Solicitation)-[:SELECTED]->(prop:Proposal)<-[:OWNS_BID]-(so:VendorOrg)
where sol.currStatus='Awarded'
with bo, so, count(sol.Number) as count_sol, sum(prop.finalPrice) as sum_finalPrice
create (bo)-[:HAS_AWARDED{awardCount: count_sol, awardVolume: sum_finalPrice}]->(so);
This query uses WITH to pass bo, so and the result of the aggregation functions count(sol.Number) and sum(prop.finalPrice) to the next context. After, these values are used to create the new relation between bo and so.

Related

Neo4j how to create multiple relationship with single Node?

Right now i am creating One to One relation with following Cypher query
#Query("MATCH (R:`User`{uuid:{uuid}}), (L:`Role`{uuid:{roleUuid}}) CREATE (R)-[r:`FILTER_ON`]->(L);")
Now my issue i have multiple roleUuid like roleUuid1,roleUuid2,roleUuid3 etc now i want to create a relationship with User(uuid) with multiple roleUuid
How it can be done in Cypher query?
Using a parameter roleUuids containing a list of role UUIDs, you can issue
MATCH (R:`User`{uuid:{uuid}}), (L:`Role`)
WHERE L.uuid IN {roleUuids}
CREATE (R)-[r:`FILTER_ON`]->(L)
or if you have an index on the uuid property:
UNWIND {roleUuids} AS roleUuid
MATCH (R:`User`{uuid:{uuid}}), (L:`Role`{uuid:roleUuid})
CREATE (R)-[r:`FILTER_ON`]->(L)
One remark: if you're on recent Neo4j versions, I'd suggest using the $parameter syntax instead of the {parameter} one to improve readability.

How could i use this SQL on cypher(neo4j)

hi how can i transform this SQL Query as CYPHER Query ? :
SELECT n.enginetype, n.Rocket20, n.Yearlong, n.DistanceOn,
FROM TIMETAB AS n
JOIN PLANEAIR AS p ON (n.tailnum = p.tailNum)
If it is requisition before using that query to create any relationship or antyhing please write and help with that one too.. thanks
Here's a good guide for comparing SQL with Cypher and showing the equivalent Cypher for some SQL queries.
If we were to translate this directly, we'd use :PLANEAIR and :TIMETAB node labels (though I'd recommend using better names for these), and we'll need a relationship between them. Let's call it :RELATION.
Joins in SQL tend to be replaced with relationships between nodes, so we'll need to create these patterns in your graph:
(:PLANEAIR)-[:RELATION]->(:TIMETAB)
There are several ways to get your data into the graph, usually through LOAD CSV. The general approach is to MERGE your :PLANEAIR and :TIMETAB nodes with some id or unique property (maybe TailNum?, use ON CREATE SET ... after the MERGE to add the rest of the properties to the node when it's created, and then MERGE the relationship between the nodes.
The MERGE section of the developers manual should be helpful here, though I'd recommend reading through the entire dev manual anyway.
With this in place, the Cypher equivalent query is:
MATCH (p:PLANEAIR)-[:RELATION]->(n:TIMETAB)
RETURN n.Rocket20,p.enginetype, n.year, n.distance
Now this is just a literal translation of your SQL query. You may want to reconsider your model, however, as I'm not sure how much value there is in keeping time-related data for a plane separate from its node. You may just want to have all of the :TIMETAB properties on the :PLANEAIR node and do away with the :TIMETAB nodes completely. Of course your queries and use cases should guide how to model that data best.
EDIT
As far as creating the relationship between :PLANEAIR and :TIMETAB nodes (and again, I recommend using better labels for these, and maybe even keeping all time-related properties on a :Plane node instead of a separate one), provided you already have those nodes created, you'll need to do a joining match, but it will help to have a unique constraints on :PLANEAIR(tailnum) :TIMETAB(tailNum) (or an index, if this isn't supposed to be a unique property):
CREATE CONSTRAINT ON (p:PLANEAIR)
ASSERT p.tailNum IS UNIQUE
CREATE CONSTRAINT ON (n:TIMETAB)
ASSERT n.TailNum IS UNIQUE
Now we're ready to create the relationships
MATCH (p:PLANEAIR)
MATCH (n:TIMETAB)
WHERE p.tailNum = n.tailNum
CREATE (p)-[:RELATION]->(n)
REMOVE n.tailNum
Now that the relationships are created, and :TIMETAB tailNum property removed, we can drop the unique constraint on :TIMETAB(tailNum), since the relationship to :PLANEAIR is all we need.
DROP CONSTRAINT ON (n:TIMETAB)
ASSERT n.tailNum IS UNIQUE

How do I refactor data two neo4j nodes to a relationship?

I'm doing an experiment with using a graph database (neo4j). I have two csv's that I imported into a neo4j datastore. I'm a little shakey on the neo terminology; so forgive me. Lets say I have:
Customer (AccountNumber, CustomerName) and
CustomerGroups (AccountNumber, GroupName).
I would like to create a new Node called groups which is comprised of the distinct GroupName from CustomerGroups. I'll call it Group.
I then want to create relationships "HAS_GROUP" from Customer to Group using the common AccountNumber from CustomerGroups.
Once the above is completed, I could delete CustomerGroups as its no longer needed.
I'm just stuck at the syntax. I can get the distinct groups from CustomerGroups with:
MATCH (n:CustomerGroups) distinct n.GROUP_NAME
and I get back about 50 distinct groups, but can't figure how to add the create statement to the results and CREATE g:Group {GroupName: n.GROUP_NAME}
I then know my followup question is how to do the MATCH to the new group using the old table with common account numbers.
FYI: I've indexed the AccountNumber in both Nodes. Both Customer and CustomerGroups have over 5 Million nodes. Not bad for a laptop (2 min to import using neo4j-import). I was impressed!
Thanks for any help you can give!
Instead of creating a CustomerGroups label and creating nodes for that, you should be able to define relationships that you would like to create in your neo4j-import. It would certainly be a lot faster too. See:
http://neo4j.com/docs/stable/import-tool-header-format.html
To your question, you could probably do something like:
MATCH (cg:CustomerGroup)
MATCH (customer:Customer {AccountNumber: cg. AccountNumber}), (group:Group {GroupName: cg.GroupName})
CREATE (customer)-[:IN_GROUP]->(group)
You'd definitely want to make sure you have indexes on :Customer(AccountNumber) and :Group(GroupName) first. But even then it would still be much slower than doing it as part of your initial import.
Also, you may or may not want MERGE instead of CREATE

Cypher: Create relationships between nodes based on a common property key id

I'm brand new to Cypher (and Stackoverflow) and am having trouble creating relationships between nodes based on share property keys.
I would like to do something like this:
MATCH (a:Person)-->()<--(b:Country)
WHERE HAS (a.id) AND HAS (b.id) AND a.id=b.id
CREATE (a)-[:LIVES]->(b);
to create a relationship between Country node and Person nodes where they share the same id.
The above creates no errors when run but doesn't create any relationships either and I know that the ids should match.
Many thanks!!
EDIT:
I think I know what is going wrong - I'm asking to match nodes that have a relationship to eachother but no relationships are set up yet hence 0 results. I have now tried:
MATCH (a:Person),
(b:Country)
WHERE HAS (a.id) AND HAS (b.id) AND a.id=b.id
CREATE (a)-[:LIVES]->(b);
and the query is running. It's a big data set so might take a while......
That worked. Had to reduce the size of my data set (down from 64k nodes) as Neo4j was taking way too long to process but once I had a smaller set it worked fine.
One minor addition for future Googlers.
per the help files as of version 3.4
The has() function has been superseded by exists() and has been removed.
The new code should read
MATCH (a:Person),
(b:Country)
WHERE EXISTS (a.id) AND EXISTS (b.id) AND a.id=b.id
CREATE (a)-[:LIVES]->(b);

Creating unique relationships in Neo4j using py2neo get_or_create

I am trying to create a graph using some nodes and relationships using py2noe. say, I'm creating a family tree.
I am creating nodes using get_or_create() so that my script doesn't create duplicates if I supply the same value again.
How can I do the same for a relationship? I can't find any reference to a get_or_create() like function for a relationship.
I want to publish (Joe)-[:son]->(John)
the first time it creates 2 nodes joe and john and a link between them.
if I re run my script, as the nodes are unique, they aren't published but a new relationship is created.
This gives me a graph with 2 nodes and n relationships where n is the number of times I run the script.
I also tried using cypher and I get the same issue. It keeps on creating relationships.
Can anyone suggest me a way to solve this problem?
Thanks.
I don't know py2neo (so there may be a wrapper for this function), but the way to achieve that would be using a Cypher MERGE which it looks like you have to run using the raw Cypher statement:
cypher_merge_result = neo4j.CypherQuery(graph_db,
"MERGE (s:Person{name:Joe})-[:SON]->(f:Person{name:John})")
That will create 2 Person nodes and 1 SON relationship, no matter how many times that you run it.
Neo4J documentation is here and it is important to understand how it works as partial matches in the MERGE statement will cause the whole pattern to be created. So if your Person nodes already exist you should match them in advance to avoid duplicate Persons being created. i.e
cypher_merge_result = neo4j.CypherQuery(graph_db,
"MATCH (s:Person{name:Joe}), (f:Person{name:John}) MERGE (s)-[:SON]->(f)")

Resources