Getting Neo4j node and relationship data without duplicates - neo4j

I have the graph below and I would like to get the 2 Task nodes (i.e. the two nodes that are displayed with dates). Then I would like to get the WAS_BOUGHT relationships and then the MAKING_USE_OF relationships. Obviously I would like this data to correlate to the given tasks being matched. I then take that data and create a Task object in my application and store a List of the WAS_BOUGHT relationships and a List of the MAKING_USE_OF relationships as properties of the object.
I tried to run the query below but I get a lot of duplicates. Every time the relationship data arrives I get the Task data again, duplicated. I would prefer to condition the data already in neo4j before parsing it through to my application. I just feel like it will be a lot more efficient that way.
MATCH (t:Task)-[r1:WAS_BOUGHT]->()
MATCH (t:Task)-[r2:MAKING_USE_OF]->()
WHERE ID(t) IN [40,60]
RETURN t, r1, r2
I can split this up into 3 queries to avoid duplicates but it then will require a connection to the database 3 times which seems really inefficient.
MATCH (t:Task)-[]->()
WHERE ID(t) IN [40,60]
RETURN t
MATCH (t:Task)-[r1:WAS_BOUGHT]->()
WHERE ID(t) IN [40,60]
RETURN r1
MATCH (t:Task)-[r2:MAKING_USE_OF]->()
WHERE ID(t) IN [40,60]
RETURN r2
Any idea how I can write a query to get the data in the format below without duplicates?
Task node, WAS_BOUGHT relationships, MAKING_USE_OF relationships for ID=40
Task node, WAS_BOUGHT relationships, MAKING_USE_OF relationships for ID=60

Here is a single row for each Task node
// find the specific task nodes and WAS_BOUGHT relatioships
MATCH (t:Task)-[r1:WAS_BOUGHT]->()
WHERE ID(t) IN [40,60]
// aggregate the WAS_BOUGHT relationships per task
WITH t, collect(r1) AS bought
// with each task find what was used to shop
MATCH (t)-[r2:MAKING_USE_OF]->()
// return the task with the aggregate WAS_BOUGHT and MAKING_USE relationships
RETURN t, bought, collect(r2) AS making_use

Related

Cypher - given relationship, get the nodes

If I do the query
MATCH (:Label1 {prop1: "start node"}) -[relationships*1..10]-> ()
UNWIND relationships as relationship
RETURN DISTINCT relationship
How do I get nodes for each of acquired relationship to get result in format:
╒════════╤════════╤═══════╕
│"from" │"type" │"to" │
╞════════╪════════╪═══════╡
├────────┼────────┼───────┤
└────────┴────────┴───────┘
Is there a function such as type(r) but for getting nodes from relationship?
RomanMitasov and ray have working answers above.
I don't think they quite get at what you want to do though, because you're basically returning every relationship in the graph in a sort of inefficient way. I say that because without a start or end position, specifying a path length of 1-10 doesn't do anything.
For example:
CREATE (r1:Temp)-[:TEMP_REL]->(r2:Temp)-[:TEMP_REL]->(r3:Temp)
Now we have a graph with 3 Temp nodes with 2 relationships: from r1 to r2, from r2 to r3.
Run your query on these nodes:
MATCH (:Temp)-[rels*1..10]->(:Temp)
UNWIND rels as rel
RETURN startNode(rel), type(rel), endNode(rel)
And you'll see you get four rows. Which is not what you want because there are only two distinct relationships.
You could modify that to return only distinct values, but you're still over-searching the graph.
To get an idea of what relationships are in the graph and what they connect, I use a query like:
MMATCH (n)-[r]->(m)
RETURN labels(n), type(r), labels(m), count(r)
The downside of that, of course, is that it can take a while to run if you have a very large graph.
If you just want to see the structure of your graph:
CALL db.schema.visualization()
Best wishes and happy graphing! :)
Yes, such functions do exist!
startNode(r) to get the start node from relationship r
endNode(r) to get the end node
Here's the final query:
MATCH () -[relationships*1..10]-> ()
UNWIND relationships as r
RETURN startNode(r) as from, type(r) as type, endNode(r) as to

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

Is it possible to query relations from two node which the number of relation greater than a certain value

I am a newbie who just started learning graph database and I have a problem querying the relationships between nodes.
My graph is like this:
There are multiple relationships from one node to another, and the IDs of these relationships are different.
How to find relationships where the number of relationships between two nodes is greater than 2,or is there a problem with the model of this graph?
Just like on the graph, I want to query node d and node a.
I tried to use the following statement, but the result is incorrect:
match (from)-[r:INVITE]->(to)
with from, count(r) as ref
where ref >2
return from
It seems to count the number of relations issued by all from, not the relationship between from-->to.
to return nodes who have more then 2 relationship between them you need to check the size of the collected rels. something like
MATCH (x:Person)-[r:INVITE]-(:Party)
WITH x, size(collect(r)) as inviteCount
WHERE inviteCount > 2
RETURN x
Aggregating functions like COLLECT and COUNT use non-aggregating terms in the same WITH (or RETURN) clause as "grouping keys".
So, here is one way to get pairs of nodes that have more than 2 INVITE relationships (in a specific direction) between them:
MATCH (from)-[r:INVITE]->(to)
WITH from, to, COUNT(r) AS ref
WHERE ref > 2
RETURN from, to
NOTE: Ideally (for clarity and efficiency), your nodes would have specific labels and the MATCH pattern would specify those labels.

neo4j - How to bring all nodes of one type in a result of relationship query?

I am sorry for the stupid question. I have two types of nodes in neo4j database, namely Recipes and Meal_Type. I am running a cypher query in neo4j that results all relationship between the two types of nodes. The query is not that special, it is the default query that returns relationship with a limit of 200 nodes.
MATCH ()-[r]->() RETURN r LIMIT 200
It is running fine. But I need, at least, all Meal_Types nodes in result regardless the rest of result. Right now it is returning 3 (sometimes 4,5 on re-running query) out of 11 Meal_Types.
I think you should fetch all of the Meal_Type nodes first and then with that result fetch a set of Recipe nodes that correspond to it.
Here is an example of what I am talking about. Fetch all of the different meal types, unless of course you have some specific ones you are interested in. Then with those meal types return a sampling of the corresponding set of recipes (200 ~= 19 * 11).
// match meal types
MATCH (mt:Meal_Type)
WITH mt
// find a sampling of the the corresponding recipes.
MATCH (mt)<-[OF_TYPE]-(r:Recipe)
RETURN mt, collect(r)[0..18] AS recipe_sample
Really? I answered that yesterday with your previous question, it's just a variation.
This should do the trick, sorting the relationships by node label:
MATCH (n)-[r]-()
RETURN r
ORDER BY head(labels(n))

Cypher query to find all paths with same relationship type

I'm struggling to find a single clean, efficient Cypher query that will let me identify all distinct paths emanating from a start node such that every relationship in the path is of the same type when there are many relationship types.
Here's a simple version of the model:
CREATE (a), (b), (c), (d), (e), (f), (g),
(a)-[:X]->(b)-[:X]->(c)-[:X]->(d)-[:X]->(e),
(a)-[:Y]->(c)-[:Y]->(f)-[:Y]->(g)
In this model (a) has two outgoing relationship types, X and Y. I would like to retrieve all the paths that link nodes along relationship X as well as all the paths that link nodes along relationship Y.
I can do this programmatically outside of cypher by making a series of queries, the first to
retrieve the list of outgoing relationships from the start node, and then a single query (submitted together as a batch) for each relationship. That looks like:
START n=node(1)
MATCH n-[r]->()
RETURN COLLECT(DISTINCT TYPE(r)) as rels;
followed by:
START n=node(1)
MATCH n-[:`reltype_param`*]->()
RETURN p as path;
The above satisfies my need, but requires at minimum 2 round trips to the server (again, assuming I batch together the second set of queries in one transaction).
A single-query approach that works, but is horribly inefficient is the following single Cypher query:
START n=node(1)
MATCH p = n-[r*]->() WHERE
ALL (x in RELATIONSHIPS(p) WHERE TYPE(x) = TYPE(HEAD(RELATIONSHIPS(p))))
RETURN p as path;
That query uses the ALL predicate to filter the relationships along the paths enforcing that each relationship in the path matches the first relationship in the path. This, however, is really just a filter operation on what it essentially a combinatorial explosion of all possible paths --- much less efficient than traversing a relationship of a known, given type first.
I feel like this should be possible with a single Cypher query, but I have not been able to get it right.
Here's a minor optimization, at least non-matching the paths will fail fast:
MATCH n-[r]->()
WITH distinct type(r) AS t
MATCH p = n-[r*]->()
WHERE type(r[-1]) = t // last entry matches
RETURN p AS path
This is probably one of those things that should be in the Java API if you want it to be really performant, though.

Resources