MERGE Nodes by a Property field - neo4j

I have different nodes that share one same property field, i need to merge these nodes into one and in the same time copy all the rest of the other properties in the merge node.
example:
(n1,g,p1) (n2,g,p2) (n3,g,p3) =>(n,g,p1,p2,p3)
Important to Note that i don't need the apoc solutions since user defined functions dosen't work in CAPS that i m working at
update :
geohash is the field that have a repeated values, so i want to merge the nodes by this field .
The CAPS team gave me this cypher query to have distinct geohash nodes from the intial graph:
CATALOG CREATE GRAPH temp {
FROM GRAPH session.inputGraph
MATCH (n)
WITH DISTINCT n.geohash AS geohash
CONSTRUCT
CREATE (:HashNode {geohash: geohash})
RETURN GRAPH
}
, however it still missing is the collect of the rest of the properties on the merged nodes.
I haven't a problem for the relationship ,cause we can copy them later from the intial graph:
FROM GRAPH inputGraph
MATCH (from)-[via]->(to)
FROM GRAPH temp
MATCH (n), (m)
WHERE from.geohash = n. AND AND to.geohash = m.geohash
CONSTRUCT
CREATE (n)-[COPY OF via]->(m)
RETURN GRAPH

It's not 100% possible in pure cypher, that's why there is an APOC procedure for that.
To merge two nodes , you have to :
create the merge node with all the properties
to create all the relationship of the nodes on the merge one
For the first part it's possible in cypher. Example :
MATCH (n) WHERE id(n) IN [106, 68]
WITH collect(n) AS nodes
CREATE (new:MyNode)
with nodes, new
UNWIND nodes as node
SET new += properties(node)
RETURN new
But for the second part, you need to be able to create relationship with a dynamic type and dynamic direction, and this is not allowed in cypher ...

Related

To get nodes and relationships between two specified nodes for review

I have a database containing millions of nodes and edge data and I want to get all the nodes and relationships data between two specified nodes.
Below is the sample data for the graph which has 7 nodes and 7 relationships.
To traverse from 1st node to 7th node I can use the variable length relationship approach and can get the nodes and relationships in between the first and 7th nodes (but in this approach we need to know the number of relationships and nodes between 1st and 7th node).
For using variable length relationship approach we have to specify the number where we will get the end node and it traverses in one direction.
But in my case I know the start and end node and don't know how many relationships and nodes are in between them. Please suggest how I can write a Cypher query for this case.
I have used the APOC spanning tree procedure where it returns ‘path’ from the 1st and 7th element, but it does not return the nodes and relationships. Can I get nodes and relationships data in return using the spanning tree procedure and how?
Is there any other way to get all nodes and relations between two nodes without using the APOC procedure?
Here is query with apoc procedure:
MATCH (start:temp {Name:"Joel"}), (end:temp {Name:"Jack"}) CALL apoc.path.spanningTree(start,{terminatorNodes:[end]}) YIELD path return path
Note: In our graph database nodes can have multi direction relations.
[Sample nodes and relationships snapshot]
: https://i.stack.imgur.com/nN9hk.png
I assume you do not want to have duplicates in your result, so my approach would be this
MATCH (start:temp {Name:"Joel"}), (end:temp {Name:"Jack"})
MATCH p=shortestPath((start)-[*]->(end))
UNWIND nodes(p) AS node
UNWIND relationships(p) AS rel
RETURN COLLECT(DISTINCT node) as nodes, COLLECT(DISTINCT rel) as rels
Might be better to use shortestPath operator to find the shortest path between two nodes.
MATCH (start:temp {Name:"Joel"}), (end:temp {Name:"Jack"})
MATCH p=shortestPath((start)-[*]->(end))
RETURN nodes(p) as nodes, relationships(p) as rels

Neo4j - Match then merge statement with a relationship not creating new nodes

When I try to add new nodes with labels (Phone, Name) that don't exist yet with a relationship to an existing node the nodes and relationships are not being created.
This is the before and after state with one existing relationship:
MATCH (n:Identity)-[a:ATTR]->(attr) RETURN *
And this is the mutation query:
MATCH (n:Identity {id:'4a028061-8dde-4f64-80c9-ae048e3f81fc'})
MERGE (n)-[na:ATTR]->(name:Name {val: 'John Smith'})
MERGE (n)-[pa:ATTR]->(p:Phone {val:2326410083})
RETURN *
I know this question is similar to Neo4J - Merge statement not creating new nodes with a relationship but, in my case, I am using filters on the nodes. What's am I missing?
Looks like the :Identity node you're trying to match to doesn't exist in the graph.
From your query, you're looking for an identity node with id:'4a028061-8dde-4f64-80c9-ae048e3f81fc', but in the graph image you supplied, if we assume the cut off caption is the id of the identity node, we can tell it starts with:'44b7'
Now it could be that the node you're trying to match on does exist, but doesn't have any outgoing :ATTR relationship (that would explain why it wouldn't be returned by your query), but that's unconfirmed. Does a node with id:'4a028061-8dde-4f64-80c9-ae048e3f81fc' exist in your graph? You haven't shown us that, and if no such node exists then the match would fail, and then there are no rows left for the remaining MERGEs to execute upon.

Generate disjoint star-like subgraphs based on equalities

Consider this toy example:
MERGE (:Obj {desc:'A',id:1})
MERGE (:Obj {desc:'A',id:2})
MERGE (:Obj {desc:'A',id:3})
MERGE (:Obj {desc:'A',id:4})
MERGE (:Obj {desc:'B',id:5})
MERGE (:Obj {desc:'B',id:6})
I have 6 different nodes, but there are only two different values for the description (so, only two classes of nodes). Suppose I want to create now a relationship SAME_AS through which all nodes having the same description will be connected. That is, that I should be able to get from a node x to all other nodes having the same description traversing SAME_AS relationships.
For the connected subcomponents I would prefer star-like graphs, where for each category the node with the smallest id acts as prototype to which all other equivalent nodes link to. (Another possibility, not as good, would be Hamiltonian paths)
So far, I only came up with this
MATCH (o1:Obj), (o2:Obj)
WHERE o1.desc=o2.desc AND o1.id<o2.id
MERGE (o1)<-[:SAME_AS]-(o2)
But it builds a clique for each class.
Better solutions required using a MATCH within a FOREACH statement, which isn't allowed in neo4j.
I don't even get whether cypher is appropriated to do this, or whether I should perform these calculations outside neo4j and only afterwards write the info within the DB.
Thanks
How about something like this
// match the objects
MATCH (o1:Obj)
WITH o1.desc AS desc, o1
// put them in ascending order so we can find the smallest
ORDER BY desc,o1.id
// collect them per description
WITH desc, collect(o1) AS objs
// connect 1..n to node 0
UNWIND RANGE(1,size(objs)-1) AS idx
WITH objs[0] AS origin, objs[idx] AS dupe
MERGE (origin)<-[:SAME_AS]-(dupe)

neo4j: REST API call to get the whole connected subgraph

Build a D3 viewer, I'd like to get all the nodes connected to one, and all the links connecting these nodes. In fact, the same thing as in the default neo4j viewer....
For example, I have
CREATE (a:Person {name:'a'})
CREATE (b:Person {name:'b'})
CREATE (c:Person {name:'c'})
CREATE (d:Person {name:'d'})
CREATE (a)-[:KNOWS]->(b)
CREATE (a)-[:KNOWS]->(c)
CREATE (b)-[:KNOWS]->(c)
CREATE (c)-[:KNOWS]->(d)
I can issue some ugly cypher query to give to the POST call, but it does not scale with medium size graphs (~100k nodes, 3M relationships).
Looking, at the posted queries in the neo4j browser, it looks like there are 2 successive one:
A) get the connected nodes
MATCH (p:Person {name:'a'})-[l:KNOWS]-(q:Person) RETURN p,q
B) get the links existing between these nodes
"START a = node(185282,185283,185284), b = node(185282,185283,185284)
MATCH a -[r]-> b
RETURN r;"
My two questions:
Is there a clean way to get list of unique nodes?
Is this two steps method the preferred one?
Again, the data can be a bit heavy, so let's keep that in mind
Thanks for the help
Alex
You can pipe the results of the first query to the second one using WITH to get all connections between Persons which the 'a' Person knows:
MATCH (p:Person)-[l:KNOWS]-(q:Person)
WHERE p.name = "a"
WITH p,q
MATCH (p)-[r]-(q)
RETURN p,r,q

merging nodes into a new one with cypher and neo4j

using Neo4j - Graph Database Kernel 2.0.0-M02 and the new merge function,
I was trying to merge nodes into a new one (merge does not really merges but binds to the returning identifier according to the documentation) and delete old nodes. I only care at the moment about properties to be transferred to the new node and not relationships.
What I have at the moment is the cypher below
merge (n:User {form_id:123}) //I get the nodes with form_id=123 and label User
with n match p=n //subject to change to have the in a collection
create (x) //create a new node
foreach(n in nodes(p): set x=n) //properties of n copied over to x
return n,x
Problems
1. When foreach runs it creates a new x for every n
2. Moving properties from n to x is replacing all properties each time with the new n
so if the 1st n node from merge has 2 properties a,b and the second c,d in the and after the set x=n all new nodes end up with c,d properties. I know is stated in the documentation so my question is:
Is there a way to merge all properties of N number of nodes (and maybe relationships as well) in a new node with cypher only?
I don't think the Cypher language currently has a syntax that non-destructively copies any and all properties from one node into another.
However, I'll present the solution to a simple situation that may be similar to yours. Let's say that some User nodes have the properties a & b, and some others have c & d. For example:
CREATE (:User { id:1,a: 1,b: 2 }),(:User { id:1,c: 3,d: 4 }),
(:User { id:2,a:10,b:20 }),(:User { id:2,c:30,d:40 });
This is how we would "merge" all User nodes with the same id into a single node:
MATCH (x:User), (y:User)
WHERE x.id=y.id AND has(x.a) AND has(y.c)
SET x.c = y.c, x.d = y.d
DELETE y
RETURN x
You can try this out in the neo4j sandbox at: http://console.neo4j.org/
With Neo4j-3.x it is also possible to merge two nodes into one using a specific apoc procedure.
First you need to download the apoc procedures jar file in your into your $NEO4J_HOME/plugins folder and start the Neo4j server.
Then you can call apoc.refactor.mergeNodes this way:
MATCH (x:User), (y:User)
WHERE x.id=y.id
call apoc.refactor.mergeNodes([x,y]) YIELD node
RETURN node
As I can see it, the resulting node would have all the properties of both x and y, choosing the values of y if both are set.

Resources