Apoc.merge.relationship() creates duplicates in Neo4j - neo4j

I am trying to create relationship between two nodes using apoc.merge.relationship, but it creates two same relationships, which I can see by search. They both have same direction and everything is the same although from query it's obvious that newLink.id is identifier. I hope someone can show me what is wrong with my cypher query.
UNWIND [{
color:'#82abd1', direction:'true', id:'q', index:0, linkType:'a',
source:'46166.a690c888-e3d5-41ed-8469-79a88cce8388', status:'approved',
target:'46163.a690c888-e3d5-41ed-8469-79a88cce8388', type:'Applies for', value:2
}] AS newLink
MATCH
(fNode:Node {id: newLink.source}),
(sNode:Node {id: newLink.target})
CALL apoc.merge.relationship(
fNode,
'Label',
{id: newLink.id},
apoc.map.clean(newLink, ['id','type'],[]),
sNode,
apoc.map.clean(newLink, ['id','type'],[])
)
YIELD rel
RETURN DISTINCT 'true';
my search query is
MATCH ()-[rel]-() RETURN COUNT(rel)

My query was finding same relationships for both (node1)-[rel]-(node2) and for (node2)-[rel]-(node1). So one way to avoid this situation is using ID(node1)>ID(node2), which compares nodes id given by neo4j.

Related

Return type matched from multiple relationships in Neo4j with Cypher

I know that you can match on multiple relationships in Neo4j, like this example in the docs:
MATCH (wallstreet {title: 'Wall Street'})<-[:ACTED_IN|:DIRECTED]-(person)
RETURN person.name
which returns nodes with an ACTED_IN or DIRECTED relationship to 'Wall Street'.
However, is there a way to get the type of the relationship in this query? That is, I would like to return not only the name, but also which relationship applies to him/her, in order to see if it was the ACTED_IN, or the DIRECTED relationship that caused the result to be output.
You can do the equivalent here:
MATCH (:Person {name: 'Oliver Stone'})-[r]->(movie)
RETURN type(r)
but that's just matching on any relationship. I would like to do this, but only with the two relationships specified in the clause.
Thanks
You no longer need additional colons in between valid edge types you are querying. otherwise you can use the variable just like you did in the unspecific edge case:
MATCH (:Movie{title: 'The Matrix'})<-[r:ACTED_IN|DIRECTED]-(person)
RETURN type(r), person.name

Return non-matching nodes while creating relationships Neo4j Cypher

I wrote a script to to batch create a bunch of relationship in neo4j. Here is the cypher:
:param batch => [{startId: 'abc123', endId: 'abc321'}, {startId: 'abc456', endId: 'abc654']
UNWIND $batch as row
MATCH (from {id: row.startId}
MATCH (to {id: row.endId}
CREATE (from)-[rel:HAS]->(to)
RETURN rel
The problem that there might be some startId/endId entries that don't match any nodes and are silently ignore. Is there a way to return the list of rows that don't match any nodes and create the relationship for the nodes that do match?
I tried OPTIONAL MATCH to fail-fast as soon an id doesn't find a startId/endId however, the query execution was really slow.
First of all, you should always try to specify a label for the node that is used to kick off a MATCH (unless the MATCH pattern uses any already-bound nodes). Otherwise, every single node in the DB must be scanned. In addition, you should consider using indexes to speed up your MATCHs (but, again, you'd need to specify the labels).
Here is a query that uses the APOC procedure apoc.do.when to create a new relationship when appropriate. It returns each row and the corresponding new relationship (or NULL if either node is not found):
UNWIND $batch as row
OPTIONAL MATCH (from:Foo {id: row.startId})
OPTIONAL MATCH (to:Foo {id: row.endId})
CALL apoc.do.when(
from IS NOT NULL AND to IS NOT NULL,
'CREATE (from)-[rel:HAS]->(to) RETURN rel',
'RETURN NULL AS rel',
{from: from, to: to}) YIELD value
RETURN row, value.rel AS rel

py2Neo.ogm shortestPath search not turning up results

I have implemented py2neo with ogm, however I cannot get the search functionality to work like it should. Below I have my cypher query (directly to the Neo4j db) with 'rpt_id' and 'country_code' as GraphObjects in the graph with those as the primary keys of the graph. The relationship between them is PART_OF.
MATCH (m:Column {name: '{rpt_id}'}), (n:Column {name:'{country_code}'}),
p = shortestPath((m)-[:PART_OF*..4]-(n))
RETURN p
I expect a response of the Tables (another ogm node) to go through to get to country_code, however, nothing is being returned.
If nodes definitely exist that match rpt_id and country_code I expect the problem is the use of ticks around your parameters. I would re-write the query as follows:
MATCH (m:Column {name: {rpt_id} }), (n:Column {name: {country_code} }), p = shortestPath((m)-[:PART_OF*..4]-(n))
RETURN p

Return all nodes and relations among nodes in path

First time asking on SO and a newby of cypher and neo4j.
I need to get all the nodes, and all their relationships, that compose the lineage of a particular node; to display them in a directed graph I need a list of nodes and a list of the relationships (links).
This is my dummy set of nodes, and this is what I want to get (nodes plus links): result
This is what I came up after hours of research and attempts:
MATCH lineage = (n:Sample {name:"P"})-[:CHILD_OF*]->(parent:Sample)
MATCH (parent)-[r_out]->(child)-[r_in]->(parent)
WHERE parent IN nodes(lineage) OR child IN nodes(lineage)
RETURN
collect(DISTINCT parent) AS nodes,
collect({ source: parent.name, rel: type(r_out), target: child.name }) AS links_out,
collect({ source: child.name, rel: type(r_in), target: parent.name }) AS links_in;
(I created two different list of relationships so i can distinguish the source and target.)
However this does not return n in the list of nodes and actually multiplicates the links, as I guess returns all the possible paths between n and all the other nodes.
I could not figure out a solution and I am also convinced it should be a much more elegant query...
Any help?
Thanks
This is what I was looking for!
MATCH lineage = (child:Sample {name:"P"})-[:CHILD_OF*]->(parent:Sample)
MATCH (n:Sample)-[r_out]->(m:Sample)-[r_in]->(n:Sample)
WHERE n IN nodes(lineage) AND m IN nodes(lineage)
RETURN
child + collect(DISTINCT parent) AS nodes,
collect(DISTINCT {source: n.name, rel: type(r_out), target: m.name}) +
collect(DISTINCT {source: m.name, rel: type(r_in), target: n.name}) AS links
The plus sign merges the results in a single array, and so now I have in a single query my two arrays of nodes and links! :)
i THINK i get your question and in case i do ... (otherwise my apologies )
Getting the nodes and getting the unique relations between all the nodes that came back is a two step process. you can see my answer here
Basically the first request gets you the nodes and then you query for all relationships where either side of the relationship is a node with one of the node ids you got back in the first query
match a-[r]-b where id(a) in [1,2...] and id(b) in [1,2,3...] return r
note that the array of integers is the same unique list of node ids from the first query.

Limiting ShortestPath in Cypher to nodes with specific properties

I am trying to figure out how to limit a shortest path query in cypher so that it only connects "Person" nodes containing a specific property.
Here is my query:
MATCH p = shortestPath( (from:Person {id: 1})-[*]-(to:Person {id: 2})) RETURN p
I would like to limit it so that when it connects from one Person node to another Person node, the Person node has to contain a property called "job" and a value of "engineer."
Could you help me construct the query? Thanks!
Your requirements are not very clear, but if you simply want one of the people to have an id of 1 and the other person to be an engineer, you would use this:
MATCH p = shortestPath( (from:Person {id: 1})-[*]-(to:Person {job: "engineer"}))
RETURN p;
This kind query should be much faster if you also created indexes for the id and job properties of Person.

Resources