I have a requirement where i want to include multiple destination nodes in my path.
My requirement:
I want to find all the suppliers and the RISK associated with the Suppliers for a particular product.
Query to return all suppliers for a Product.
match path =(p:Product{name:"Product2"}) <-[*..10] -(:Supplier)
return path
This query returns me all the suppliers for a particular product
Query to return suppliers affected by RISK for a product
match path =(p:Product{name:"Product2"}) <-[*..10] -(:Supplier)-[:AFFECTEDBY]-(:RISK)
return path
As you can see the 2 suppliers (name:"SupplierN+1") were not retrieved in the above graph
Can you please help me with the query to retrieve BOTH Suppliers (3 suppliers) and RISK associated with for a particular product.
Thanks
MATCH p:Product{name:"Product2"}) <-[*..10] -(s:Supplier)
OPTIONAL MATCH s-[:AFFECTED_BY]-(r:RISK)
RETURN s, r, p
OPTIONAL MATCH is like OUTER JOIN of SQL. It will optionally match :RISK nodes for the :SUPPLIER. It will return all :SUPPLIER nodes which have or don't have relation to :RISK nodes.
Related
[newbie question] I'm kinda in doubt if it's better using specific relationships or labels, but first let me give you a little bit more context.
Suppose that the graph should be able to answer the following questions/queries:
Given a person, return all the emails associated;
Given a person, return all the contacts;
I've come up with these 2 possible models:
They're both able to fulfill the required requests with the following queries:
First model:
MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY]-(e:Email)
RETURN p.name AS Name, e.contact AS Contact
MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY]-(c:Contact)
RETURN p.name AS Name, c.contact AS Contact
Second model:
MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY_EMAIL]-(c:Contact)
RETURN p.name AS Name, c.contact AS Contact
MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY_FAX]-(c:Contact)
RETURN p.name AS Name, c.contact AS Contact
UNION ALL
MATCH (p)-[:REACHABLE_BY_EMAIL]-(c2:Contact)
RETURN p.name AS Name, c2.contact AS Contact
But I'm wondering if there's a best practice to follow in this case. I mean, I know that having specific relationships in some cases is better since we reduce the number of nodes involved in the query (instead of filtering later by some property), but I feel like that in this case we can achieve the same result (maybe also in performance) by considering different labels.
Both of your models will work fine. But to obtain the best performance, you can combine these two models into a single one. Like this:
All the Contact nodes that store emails, will have Email label as well.
All the Contact nodes that store faxes will have Fax label as well.
Relationship type between Person and Email types node will be REACHABLE_BY_EMAIL
Relationship type between Person and Fax types node will be REACHABLE_BY_FAX
Using this model, you can easily query a person's email or by these queries:
MATCH (p:Person)-[:REACHABLE_BY_EMAIL]->(email)
RETURN p, email
MATCH (p:Person)-[:REACHABLE_BY_FAX]->(fax)
RETURN p, fax
Note, that I have not specified Email or Fax labels in the query, as they are redundant.
Also, now you can query your the emails and faxes, using simply
MATCH (e:Email) RETURN e
MATCH (f:Fax) RETURN f
If the need arises.
You can also use
(:Person)-[:REACHABLE_BY]->(:Contact)-[:HAS_TYPE]->(:ContactType)
with 'Fax', 'Phone', 'Email' as ContactType nodes.
In your queries, using directions will help you speed up things. Your 2nd query of the second model can be written as
MATCH (p:Person {name:"Bob"})-->(c:Contact)
RETURN p.name AS Name, c.contact AS Contact
For the model I suggest, the queries would be:
MATCH (p:Person {name:"Bob"})-->(c:Contact)-->(:ContactType {name:'Email'})
RETURN p.name AS Name, c.contact AS Contact
and
MATCH (p:Person {name:"Bob"})-->(c:Contact)
RETURN p.name AS Name, c.contact AS Contact
Env - Neo4j 4.0 enterprise
Plugins - GDS and apoc
I have a data in neo4j like below -
CREATE (a:hotel {hotel_id:'A'}),
(b:hotel {hotel_id:'B'}),
(c:hotel {hotel_id:'C'}),
(d:hotel {hotel_id:'D'}),
(e:hotel {hotel_id:'E'}),
(f:hotel {hotel_id:'F'}),
(g:hotel {hotel_id:'G'}),
(h:hotel {hotel_id:'H'}),
(i:hotel {hotel_id:'I'}),
(a)-[:HAS]->(b),
(b)-[:HAS]->(c),
(c)-[:HAS]->(d),
(d)-[:HAS]->(e),
(e)-[:HAS]->(f),
(f)-[:HAS]->(g),
(g)-[:HAS]->(h),
(h)-[:HAS]->(i),
(ap:hotel_loc {loc_id:'pp1A'}),
(bp:hotel_loc {loc_id:'pp1B'}),
(cp:hotel_loc {loc_id:'pp1C'}),
(dp:hotel_loc {loc_id:'pp1D'}),
(ep:hotel_loc {loc_id:'pp1E'}),
(fp:hotel_loc {loc_id:'pp1F'}),
(gp:hotel_loc {loc_id:'pp1G'}),
(hp:hotel_loc {loc_id:'pp1H'}),
(ip:hotel_loc {loc_id:'pp1I'}),
(a)-[:HAS_JUNC]->(ap),
(b)-[:HAS_JUNC]->(bp),
(c)-[:HAS_JUNC]->(cp),
(d)-[:HAS_JUNC]->(dp),
(e)-[:HAS_JUNC]->(ep),
(f)-[:HAS_JUNC]->(fp),
(g)-[:HAS_JUNC]->(gp),
(h)-[:HAS_JUNC]->(hp),
(i)-[:HAS_JUNC]->(ip);
2 scenerios
1. List of the all node starting from
given a loc_id (example pp1F), i need to get all the nodes(hotel) and their associated :HAS_JUNC nodes.
f,pp1F
g,pp1G
h,pp1H
i,pp1I
List of all until the end.
given a loc_id (example pp1C), i need to all the nodes until pp1C
a,pp1A
b,pp1B
c,pp1C
I tried this query, but no results -
MATCH s= (h1:hotel)-[:HAS_PROPERTY]->(start:hotel_propert {property_id:"pp1A"}),
e= (h2:hotel)-[:HAS_PROPERTY]->(end:hotel_propert {property_id:"pp1C"})
WITH h1, h2, s,e match p=(h1)-[:HAS*]->(h2) RETURN s,p,e
Any help is highly appreciated.
To get the hotels that have a direct HAS_JUNC relationship to a specific hotel_loc (whose id is assumed to be in the loc_id parameter) :
MATCH (a:hotel)-[:HAS_JUNC]->(ap)
WHERE ap.loc_id = $loc_id
RETURN ap, COLLECT(a) AS directly_connected_hotels
To get all the hotels connected to a specific hotel_loc:
MATCH (a:hotel)-[:HAS *0..]->()-[:HAS_JUNC]->(ap)
WHERE ap.loc_id = $loc_id
RETURN ap, COLLECT(a) AS connected_hotels
In the variable-length relationship pattern [:HAS *0..], the 0 lower bound means that the pattern is allowed to match paths in which the HAS relationship does not exist.
According to this post I tried to map all related entities in a list.
I used the same query into the post with a condition to return a list of User but it returns duplicate object
MATCH (user:User) WHERE <complex conditions>
WITH user, calculatedValue
MATCH p=(user)-[r*0..1]-() RETURN user, calculatedValue, nodes(p), rels(p)
Is it a bug? I'm using SDN 4.2.4.RELEASE with neo4j 3.2.1
Not a bug.
Keep in mind a MATCH in Neo4j will find all occurrences of a given pattern. Let's look at your last MATCH:
MATCH p=(user)-[r*0..1]-()
Because you have a variable match of *0..1, this will always return at least one row with just the user itself (with rels(p) empty and nodes(p) containing only the user), and then you'll get a row for every connected node (user will always be present on that row, and in the nodes(p) collection, along with the other connected node).
In the end, when you have a single user node and n directly connected nodes, you will get n + 1 rows. You can run the query in the Neo4j browser, looking at the table results, to confirm.
A better match might be something like:
...
OPTIONAL MATCH (user)-[r]-(b)
RETURN user, calculatedValue, collect(r) as rels, collect(b) as connectedNodes
Because we aggregate on all relationships and connected nodes (rather than just the relationships and nodes for each path), you'll get a single row result per user node.
I have a bunch of venues in my Neo4J DB. Each venue object has the property 'catIds' that is an array and contains the Ids for the type of venue it is. I want to query the database so that I get all Venues but they are ordered where their catIds match or contain some off a list of Ids that I give the query. I hope that makes sense :)
Please, could someone point me in the direction of how to write this query?
Since you're working in a graph database you could think about modeling your data in the graph, not in a property where it's hard to get at it. For example, in this case you might create a bunch of (v:venue) nodes and a bunch of (t:type) nodes, then link them by an [:is] relation. Each venue is linked to one or more type nodes. Each type node has an 'id' property: {id:'t1'}, {id:'t2'}, etc.
Then you could do a query like this:
match (v:venue)-[r:is]->(:type) return v, count(r) as n order by n desc;
This finds all your venues, along with ALL their type relations and returns them ordered by how many type-relations they have.
If you only want to get nodes of particular venue types on your list:
match (v:venue)-[r:is]-(t:type) where t.id in ['t1','t2'] return v, count(r) as n order by n desc;
And if you want ALL venues but rank ordered according to how well they fit your list, as I think you were looking for:
match (v:venue) optional match (v)-[r:is]->(t:type) where t.id in ['t1','t2'] return v, count(r) as n order by n desc;
The match will get all your venues; the optional match will find relations on your list if the node has any. If a node has no links on your list, the optional match will fail and return null for count(r) and should sort to the bottom.
I am trying to query a graph to return all of the paths with a set of specified relationships.
The graph I have contains the following nodes: Person
The relationships which connect two people are: knows, married
So an example of some data are:
c:Person-[:knows]->b:Person
a:Person-[:married]->c:Person
d:Person-[knows]-> a:Person
In my query I would like to be able to find all paths that contain both relationships 'knows' and 'married'; however, I don't care about the ordering of such relationships in the paths. For example, my query should return the following paths:
1) a:Person-[:married]->c:Person-[:knows]->b:Person
2) d:Person-[:knows]->a:Person-[:married]->c:Person
I tried the following query
MATCH p=(a)-[:KNOWS|MARRIED*1..3]-(b)
RETURN p
However, it returned the paths only having knows relationship or the paths only having married relationship, but not both.
Is there any way of finding the paths I want? Many thanks!
You can try this
MATCH p=(a)-[rel*]-(b)
WHERE type(rel)='KNOWS' OR type(rel)='MARRIED'
RETURN p
It will provide you all paths
MATCH p = (a:Person)-[rels:KNOWS|MARRIED*]->(b:Person)
WITH p, EXTRACT(r IN rels | TYPE(r)) AS types
WHERE 'KNOWS' IN types AND 'MARRIED' IN types
RETURN p