Neo4j how to create multiple relationship with single Node? - neo4j

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.

Related

Create relationship with properties using a query in Cypher

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.

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

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)")

How to create a new relationship in Neo4j, starting from an existing one, using a Cypher query?

Is there a simple way to create a new relationship in Neo4j, starting from an existing one?
Starting from the actor-director-movie database used in the tutorials, what I would like to do is to get all the {(actor1),(actor2)} couples of nodes in the graph satisfying the relationships:
(actor1)-[:ACTED_IN]->(movie)<-[:ACTED_IN]-(actor2)
and use them to create a new relationship like:
(actor1)-[:ACTED_IN_THE_SAME_MOVIE_AS]-(actor2)
in whatever direction (I am interested in both directed and undirected graphs).
Is there a way to do this with a simple Cypher query?
Many thanks,
sTe
Using the sample movie dataset:
MATCH (actor1:Person)-[:ACTED_IN]->(:Movie)<-[:ACTED_IN]-(actor2:Person)
WITH actor1, actor2
MERGE (actor1)-[:ACTED_IN_THE_SAME_MOVIE_AS]-(actor2)
I'd do that :
MATCH (actor1)-[:ACTED_IN]->()<-[:ACTED_IN]-(actor2)
CREATE UNIQUE (actor1)-[:ACTED_IN_THE_SAME_MOVIE_AS]-(actor2)
which is basically what you said. Relations are uni-directional (no way around), but the api (Cypher queries or Traversal) can read them both ways (so it doesn't really matter which way your create them in some cases).
To check if what you did is ok, you can run the following :
MATCH (actor1)-[:ACTED_IN_SAME_MOVIE]-(actor2)
RETURN actor1, actor2

How can a cypher query be written to create hyperedges?

I have a graph with offers and customers. A customer can share an offer with another customer, so when this happens, I create a hyperedge.
(CustomerA)-[:SHARED_OFFER]->(newNode)
(newNode)-[:FOR_OFFER]->(offer)
(newNode)-[:SHARED_WITH]->(customers) (this can be many customers)
Now if another customer B shares the same offer with others, I would want a new node created to represent this relationship.
Is there a way to accomplish all this in one Cypher query?
I am using:
start c=node:node_auto_index(name="C1"), o=node:node_auto_index(name="Offer"), sharedCustomer=node:node_auto_index(name="C2")
create unique c-[:SHARED_OFFER]->(sharedOffer)-[:FOR_OFFER]->(o), (sharedOffer)-[:SHARED_WITH]->(sharedCustomer)
which works for the first time. See the console at: http://console.neo4j.org/r/76no2g
This query correctly created relationships when C1 shared Offer with C2.
Executing the query for the case when C2 now shares Offer with C3 causes the same node to be reused---that's not what I want. There should be a new node created from C2 with the SHARED_OFFER relationship. Here is the query:
start c=node:node_auto_index(name="C2"), o=node:node_auto_index(name="Offer"), sharedCustomer=node:node_auto_index(name="C3")
create unique c-[:SHARED_OFFER]->(sharedOffer)-[:FOR_OFFER]->(o), (sharedOffer)-[:SHARED_WITH]->(sharedCustomer)
Any help is appreciated.
Note: I'm using 1.8.1 REST, so trying to accomplish this all in one go rather than in parts.
simply don't use create unique but just create. but remember to first specify all nodes you got in the path in the start clause and leave the param sharedOffer always unspecified so the create command will create just the unspecified elements.
update use create instead of create unique and filter on existing relations (or use 2 queries - one to check whether an sharedOffer already exists with C1 and second to update sharedOffer with C3):
START c=node:node_auto_index(name="C1"), o=node:node_auto_index(name="Offer"), sharedCustomer=node:node_auto_index(name="C2")
WHERE not(c-[:SHARED_OFFER]->(sharedOffer)-[:FOR_OFFER]->(o))
CREATE c-[:SHARED_OFFER]->(sharedOffer)-[:FOR_OFFER]->(o), (sharedOffer)-[:SHARED_WITH]->(sharedCustomer)

Resources