How do I create a transitive relationship which maps back to the same initial label.
I am trying to map data from tables that go something like this :-
A -> B -> C -> A
B has the index column from A, and C has the index column from B and A (multiple). It is a kind of transitive relationship, wherein I need to map a specific row in A back to different rows in A. How do I go about doing this?
This is to be done on the labels for the whole data set, and not to be filtered for any given id. The labels are already existing in the db.
If you already have relations from A->B and B->C, then it can be simply achieved as follows, assuming the relationship type to be X:
MATCH (a:A)-[:X]->(:B)-[:X]->(c:C)
MERGE (c)-[:X]->(a)
This will create a relationship between every C and A, when they are linked via B
Related
I have a graph where if have the following constructs:
(a)-[b:Input]->(c:Data)-[e:Output]->(f)
i want to replace b,c,e with a relationship with the label from c:
(a)-[n:Data]->(f)
The label should be generated automatically. I have multiple labels for c like: Data, AMC, Door, New_HS etc..
So the label of the new created relationship should be created like this:
[n:title = c.Label]
We cannot create a relationship based on a property. You need to create a new relationship and change the type (or relationship name) to your data label name. I used an apoc function to change (or update) that. What I did is
Find all nodes and relationship that are attached to Data
Create the needed relationship but use a dummy relationship type: REL
Use apoc function apoc.refactor.setType to change the relationship type from REL to c.label
Don't forget to remove the dummy relationship REL
Match (a)-[:Input]->(c:Data)-[:Output]->(f)
CREATE (a)-[r:REL]->(f)
WITH a, r, c, f
CALL apoc.refactor.setType(r, c.label)
YIELD input, output
WITH a, c, f
MATCH (a)-[rel:REL]->(f)
DELETE rel
RETURN a, f
BEFORE:
AFTER:
Given the following schema / data set:
(a:A1)-[ONE]->(b:B1)-[TWO]->(c:C1)
(a:A1)-[ONE]->(b:B1)-[TWO]->(c:C2)
(a:A1)-[ONE]->(b:B2)-[TWO]->(c:C3)
(a:A2)-[ONE]->(b:B3)
(a:A2)-[ONE]->(b:B4)-[TWO]->(c:C4)
(a:A2)
I'm trying to assemble a query for some a properties, a list of b properties (list of strings), and finally a list of c property lists (list of list of strings). I'm pretty close using collect() but running into an issue keeping track of which c's belong to which b's.
The query I seek would produce a single row per a (2 rows for given data set), notice that the data can be sparse, thus an empty array in the results indicating hierarchy:
"A1", ["B1", "B2"], [["C1","C2"],["C3"]]
"A2", ["B3", "B4"], [[],["C4"]]
When you aggregate using COLLECT [or any other aggregation], the other, uncollected [unaggregated] values in the row serve as the aggregation key, so only rows that share all the other values will match. For your query, you basically need to stack COLLECTs in two separate steps like so, to first get lists of c keyed by a and b, and then collect all of the bs and all of the lists of cs keyed by a, like so:
MATCH (a) - [:ONE] -> (b)
OPTIONAL MATCH (b) - [:TWO] -> (c)
WITH a, b, COLLECT(c.property) AS cs
WITH a, COLLECT(b.property) AS bs, COLLECT(cs) AS cs_per_b
RETURN a.property, bs, cs_per_b
You can replace property with whatever property you want to get from the node, and if it's not a node property, but label or other value, just replace the whole expression inside COLLECT( ). You'll also get empty lists inside cs_per_b this way if there are no cs, as desired.
Although your question states you want to list node "properties", your sample results list node labels instead.
To display the node labels, the following query should work:
MATCH (a)-[:ONE]->(b)
OPTIONAL MATCH (b)-[:TWO]->(c)
WITH a, b, COLLECT(DISTINCT LABELS(c)[0]) AS lcs
RETURN LABELS(a)[0] AS la, COLLECT(LABELS(b)[0]) AS lb, COLLECT(lcs) AS lc;
The query assumes that it is sufficient to use the ONE and TWO relationship types to distinguish between the Ax, Bx and Cx node labels, and that those nodes only have a single label. It uses an OPTIONAL MATCH for the TWO relationship since your sample results imply that it is optional.
I would like to create tabular format list of data lineage so that user can easily identify source table and columns from DWH tables using Excel filter function.
But the following Cypher code does not work.
MATCH(a:DB {TABLE:'CONT'})-[b:RELATED*1..3]->(c:DB)
WHERE ALL ( tmp IN b WHERE tmp.CLAUSE IN ['where','join','unknown'] )
RETURN a.table,a.column,b.clause,c.table,c.column
LIMIT 200
I got the following error.
Type mismatch: expected Map, Node or Relationship but was Collection<Relationship> (line 3, column 25 (offset: 147))
"RETURN a.table,a.column,b.clause,c.table,c.column"
If I specify only "RETURN a,b,c", I got the following.
a b c
{"TABLE":"TXX","COLUMN":"CXX","DB":"DXX"} [{"CLAUSE":"unknown"}] {"TABLE":"TYYY","COLUMN":"CYYY","DB":"DYYY"}
But I want to get as below.
TABLE,COLUMN,DB,CLAUSE,TABLE,COLUMN,
"TXX","CXX","DXX","unknown","TYYY","CYYY","DYYY"
How can I achieve this?
So, because the relationship you've bound to b is a variable length relationship of 1 to 3 actual relationships, when you reference b, you get a collection of those relationships, not a single relationship.
You can see that in your output when just using a, b, and c, note the brackets around the unknown clause; there could be up to 2 other objects in that collection. For some data, that "RETURN a, b, c" might look like this:
{"TABLE":"TXX","COLUMN":"CXX","DB":"DXX"} [{"CLAUSE":"unknown"}, {"CLAUSE":"join"}, {"CLAUSE":"where"}] {"TABLE":"TYYY","COLUMN":"CYYY","DB":"DYYY"}
That's why returning b.clause doesn't make sense, since you're asking for a property from a list instead of some kind of object.
You can probably do an UNWIND b as somethingElse...then do somethingElse.clause and have that work. UNWIND changes a list of something into rows, but be aware that if there are multiple :RELATED relationships, they will each appear in their own row in combination with a and c.
for example:
a-[r]->b, there are multi r between the two nodes, each r.userId is unique.
(eg: a-[r:R {userId:"user1"}]->b, (a-[r:R{userId:"user2"}]->b,
and the same for a-[r]->c
And the situation is a-[r]->b has a relationship: r.userId = amdin, but a-[r]->c doesn't have this relationship.
how can i only return c.
i try to create cypher:
"MATCH (a:SomeLabel)-[r:SomeR]->(any:SomeLabel) "
"WHERE id(a)=0 AND r.userId <> \"admin\" "
"RETURN any";
but this will also return b ,because a->b has other relationship: r.userId=xxxx
how can i write the cypher to return nodes not inculde user.Id="admin"......
If you not clearly understand what i say,please let me know....i need your help for this case..thanks
I draw a picture below, multi relationship named sr but with different properties (userId is unique),
and i want to find all nodes that related to node A, but not contains sr {userId:admin}, i add a red underline there. So as in the picture, node B has the relationship sr {userId:admin}, so i only want to return node C, no node B
For showing simple representations of graph problems, graphgists are really helpful as people can explore the data.
I've created one based on your description: http://gist.neo4j.org/?94ef056e41153b116e4f
To your problem, you can collect all usernames involved in the relationships per pair of nodes and filter based on those:
MATCH (a { name:'A' })-[r:sr]->b
WITH a,b, collect(r.name) AS usernames
WHERE NOT 'admin' IN usernames
RETURN a, b
Your question is pretty unclear. My interpretation is that you want to find nodes c that are not connected to a node a with a relationship of type R.
You basically want to do a negative match aka search for a pattern that does not exist. Negative patterns can be retrieved using a where not:
MATCH (a:SomeLabel), (c:SomeLabel)
WHERE ID(a)=0 AND NOT (a)-[:R]->(c)
RETURN c
This returns a list of all SomeLabel nodes not being connected to a.
See http://docs.neo4j.org/chunked/stable/query-where.html#query-where-patterns in the reference manual.
I'm working on a project modeling product use patterns and I'm having trouble identifying the best way to make an exact match to a single pattern
In the model I have several "product_pattern" nodes acting as the center or hub to several nodes representing various products. Each product node is unique and can be connected to any product_pattern. A series of product pattern nodes may look like:
--pattern_1
--- Product A
--- Product B
--- Product C
--pattern_2
--- Product A
--- Product B
--- Product C
--- Product D
--pattern_3
--- Product B
--- Product C
I would like to query the graph for product_patterns that use products B and C and ONLY B and C. If I just used:
Start b = node(16), c = node(37)
MATCH (b)<-[:PRODUCT_USED]-(n)-[:PRODUCT_USED]->(c)
RETURN n
I would have all product_patterns returned because they all have relationships to B and C. To Remove matches that have additional relationships from what I'm querying I foresee two strategies..
Create a property in each pattern node of product_pattern.num_products to use against a WHERE clause after the initial MATCH. In this case the num_products property would have to match '2' for nodes with relationships ONLY to B and C. My concern here is that I have to dig into each returned node for properties and popular products will make the return list much larger.
Create a WHERE NOT clause for every other product in the graph that I don't won't a relationship to... not ideal and most likely traversing the entire graph.
Are there any elegant ways to confirm that your query returns exactly the relationship match you ask for and not nodes that match your query but also have additional relationships?
Can you try this:
Start b = node(16), c = node(37)
MATCH (b)<-[:PRODUCT_USED]-(n)-[:PRODUCT_USED]->(c)
WHERE length((n)-[:PRODUCT_USED]->(c)) == 2
RETURN n