neo4j bulk insert using cypher - neo4j

How do i insert the following into neo4j
create (st:serviceticket {name:'SRT_519'})
with st as st
match (st:serviceticket) where st.name='SRT_519'
match (d:ProductID) where d.name ='PRD_1014'
with st as st , d as d
merge (d)-[:SERVICE_TICKETID]->(st);
create (st:serviceticket {name:'SRT_520'})
with st as st
match (st:serviceticket) where st.name='SRT_520'
match (d:ProductID) where d.name ='PRD_1004'
with st as st , d as d
merge (d)-[:SERVICE_TICKETID]->(st);
if i am having multiple records like this to insert how can i insert all of them at a shot.Please help me.

I'll assume that nodes for your products already exist.
Remember that your "st" is a reference and you are trying to assign the same reference twice in one batch.
The first step is to give your service tickets separate references
match (d:ProductID), (e:ProductID)
where d.name ='PRD_1014'and
e.name ='PRD_1004'
create (st519:serviceticket {name:'SRT_519'})
create (st520:serviceticket {name:'SRT_520'})
merge (d)-[:SERVICE_TICKETID]->(st519)
merge (e)-[:SERVICE_TICKETID]->(st520)

If you use parameters, you can provide an array of pairs:
you should have an index or constraint on :ServiceTicket(name) and :ProductID(name)
WITH [['SRT_519','PRD_1014']] as data
FOREACH (pair in data |
MERGE (st:ServiceTicket {name:data[0]}),(d:ProductID {name:data[1]})
MERGE (d)-[:SERVICE_TICKETID]->(st);
)

Related

How to log when a relation already exist?

I have created a hierarchical tree to represent the organization chart of a company on Neo4j, which is like the picture below.
When I insert a lot of relation with a LOAD CSV, I use this request:
LOAD CSV WITH HEADERS FROM "file:///newRelation.csv" AS row
MERGE (a:Person {name:row.person1Name})
MERGE(b:Person {name:row.person2Name})
FOREACH (t in CASE WHEN NOT EXISTS((a)-[*]->(b)) THEN [1] ELSE [] END |
MERGE (a)-[pr:Manage]->(b) )
With this request, I only create the relationship if the two people do not already have a hierarchical relationship.
How to save (log) the list of relationships that are not created because the test below fail?
CASE WHEN NOT EXISTS((a)-[*]->(b)
You need to move the existence check to a level above the foreach:
LOAD CSV WITH HEADERS FROM "file:///newRelation.csv" AS row
MERGE (a:Person {name:row.person1Name})
MERGE(b:Person {name:row.person2Name})
WITH a, b, row,
CASE WHEN NOT exists((a)-[*]->(b)) THEN [1] ELSE [] END AS check
FOREACH (t IN check |
MERGE (a)-[pr:Manage]->(b)
)
WITH a, b, row, check WHERE size(check) = 0
RETURN a, b, row

Cypher: Adding properties to relationship as distinct values

What I'm trying to do is to write a query - I already made it a webservice(working on local machine, so I get the name and people as parameters) - which connects people who share the same hobbies and set the hobbies as the relationship property as an array.
My first attempt was;
MERGE (aa:Person{name:$name})
WITH aa, $people as people
FOREACH (person IN people |
MERGE (bb:Person{name:person.name})
MERGE (bb)-[r:SHARESSAMEHOBBY]->(aa)
ON MATCH SET r.hobbies = r.hobbies + person.hobby
ON CREATE SET r.hobbies = [person.hobby])
However this caused duplicated property elements like ["swimming","swimming"]
I'm trying to set only unique properties. Then I tried the following query;
MERGE (aa:Person{name:$name})
WITH aa, $people as people FOREACH (person IN people | MERGE (bb:Person{name:person.name}) MERGE (bb)-[r:SHARESSAMEHOBBY]->(aa)
WITH r, COALESCE(r.hobbies, []) + person.hobby AS hobbies
UNWIND hobbies as unwindedHobbies
WITH r, collect(distinct, unwindedHobbies) AS unique
set r.as = unique)
However now it gives me syntax error;
errorMessage = "[Neo.ClientError.Statement.SyntaxError] Invalid use of WITH inside FOREACH
Any help is appreciated.
This should work:
MERGE (aa:Person {name: $name})
WITH aa
UNWIND $people AS person
MERGE (bb:Person {name: person.name})
MERGE (bb)-[r:SHARESSAMEHOBBY]-(aa)
WITH r, person, CASE
WHEN NOT EXISTS(r.hobbies) THEN {new: true}
WHEN NOT (person.hobby IN r.hobbies) THEN {add: true}
END AS todo
FOREACH(ignored IN todo.new | SET r.hobbies = [person.hobby])
FOREACH(ignored IN todo.add | SET r.hobbies = r.hobbies + person.hobby);
You actually had 2 issues, and the above query addresses both:
If a SHARESSAMEHOBBY relationship already existed in the opposite direction (from aa to bb), the following MERGE clause would have caused the unnecessary creation of a second SHARESSAMEHOBBY relationship (from bb to aa):
MERGE (bb)-[r:SHARESSAMEHOBBY]->(aa)
To avoid this, you should have used a non-directional relationship pattern (which is is permitted by MERGE, but not CREATE) to match a relationship in either direction, like this:
MERGE (bb)-[r:SHARESSAMEHOBBY]-(aa)
You needed to determine whether it is necessary to initialize a new hobbies list or to add the person.hobby value to an existing r.hobbies list that did not already have that value. The above query uses a CASE clause to assign to todo either NULL, or a map with a key indicating what additional work to do. It then uses a FOREACH clause to execute each thing to do, as appropriate.

neo4j match node in array order by input

I am trying to implement https://neo4j.com/blog/moving-relationships-neo4j/ pointer functionality for using it as a team order machine.See http://imgur.com/a/MViF0 for a model. I am using this cypher query.
MERGE (list:LIST)
WITH list
MATCH (u) WHERE ID(u) IN [421, 419, 420]
MERGE (team:TEAM{name: u.name})
MERGE (team)-[:PARTOF]->(list)
WITH collect(team)as elems,list
FOREACH (n IN RANGE(0, LENGTH(elems)-2) |
FOREACH (prec IN [elems[n]] |
FOREACH (next IN [elems[n+1]] |
MERGE (prec)-[:NEXT]->(next))))
with list
MATCH (elem:TEAM) WHERE NOT (elem)<-[:NEXT]-()
MERGE (list)-[:POINTER]->(elem)
Now this works quite nicely, but I have only one problem. This line:
MATCH (u) WHERE ID(u) IN [421, 419, 420]
returns my original teams ordered by id, but I would like to define my order by the pattern in the [421,419,420] pattern, like a function that
return * order by my array input.
Keep in mind that it should work for any amount of teams,this is just an example. And that my original team node isn't labeled a team but something else, so we make a duplicate every time. Any input appreciated, thanks.
Try to use the statement "unwind":
MERGE (list:LIST)
WITH list
UNWIND [421, 419, 420] as uid
MATCH (u) WHERE id(u) = uid
MERGE (team:TEAM{name: u.name})
...
[Update] Of course, it is possible to know the order manually for each node:
MERGE (list:LIST)
WITH list, [3871013, 3871011, 3871012] as ids
MATCH (u) WHERE ID(u) IN ids
WITH list, u,
FILTER(x in RANGE(0,size(ids)-1) WHERE ids[x] = id(u)) as orderIndex
ORDER BY orderIndex[0] // Sort by node position in the array of identifiers
MERGE (team:TEAM{name: u.name})
...

Cypher: How to use FOREACH on an array of objects to create multiple nodes and multiple relationships

I am having trouble with the fetch described in the title of this question. My attempt is the following string:
FOREACH (_tabobj IN {_tabarray} |
MATCH (a:Superlabel),(b)
WHERE a.id = {_parentid} AND b.id = _tabobj.id
MERGE (a)-[r:INCLUDES]->(b {
name : _tabobj.name
})
I am trying to only create the relationship if it is not already in the database and nothing if the relationship is already in the database. Also trying to only create the b node if it is not already in the database and nothing if the b node is already in the database.
I am very grateful for help you can offer
How about something like this:
MATCH (a:Superlabel {id: {_parentid}})
WITH a, tabarray IN {_tabarray}
UNWIND tabarray AS tabobj
MATCH (b {id: tabobj.id)
MERGE (a)-[r:INCLUDES]->(b {name: tabobj.name})
I generally use FOREACH as a last resort ;)
And a simpler solution:
MATCH (a:Superlabel {id: {_parentid}}), (b)
WHERE b.id IN EXTRACT(tabobj IN {_tabarray} | tabobj.id)
MERGE (a)-[r:INCLUDES]->(b {name: tabobj.name})
An important consideration for both of these queries: When matching the b node on the id property the database index (if you have one) won't be used because indexes are for a label / property pair. Specifying a label for b, if applicable, could help performance.

Neo4j, Cypher: Connect existing nodes in the graph in form of a sorted linked list

I have a problem to connect the list of movies in the database in form of a sorted linked list (in a single cypher query).
Number of movie nodes: 25L
MATCH (movie:Movie)
WITH movie
ORDER BY movie.rating DESC
WITH collect(movie) as p
FOREACH (n IN nodes(p)| CREATE PREV_MOVIE-[:NextMovie]->(n) )
RETURN p
This will need reference to the previous node PREV_MOVIE and the current node n in the FOREACH to create a relationship between the two. How to find the reference to the previous node PREV_MOVIE here, or is there any other way to do the same?
you need to apply some FOREACH magic:
MATCH (movie:Movie)
WITH movie
ORDER BY movie.rating DESC
WITH collect(movie) as p
FOREACH(i in RANGE(0, length(p)-2) |
FOREACH(p1 in [p[i]] |
FOREACH(p2 in [p[i+1]] |
CREATE UNIQUE (p1)-[:PREV_MOVIE]->(p2))))
In the tutorial part of the Neo4j Documentation there is a Linked-list chapter, maybe that will help you:
http://docs.neo4j.org/chunked/stable/cypherdoc-linked-lists.html

Resources