How to show (graphically) transitive relationships in neo4j without altering the data - neo4j

Let's say my data include nodes of the type Person, Company and Country.
A person WORKS_AT a company and a company IS_IN a country.
CREATE (Person {name:"Paul"});
CREATE (Company {brand:"BG"});
CREATE (Country {code:"UK"});
MATCH (person {name:"Paul"}),(company {brand:"BG"}) CREATE (person)-[worksat:WORKS_AT]->(company) return person,worksat,company
MATCH (company {brand:"BG"}),(country {code:"UK"}) CREATE (company)-[isin:IS_IN]->(country) return company,isin,country
So what i want is to be able to see the person->country data in a visual graph way, in the neo4j default browser, bypassing completely the company node in between (which should not be visible).
But without creating a direct permanent relationship between the Person node and the Country node.
Thanks in advance.

You can use virtual relationships in the graphical result using APOC Procedures (these are not saved to your graph data).
Here's how this would work, provided that the nodes are labeled accordingly (your above creation queries aren't adding labels, so definitely fix that):
MATCH (p:Person)-[:WORKS_AT]->()-[:IS_IN]->(c:Country)
CALL apoc.create.vRelationship(p,'WORKS_IN',{},c) yield rel
RETURN p, rel, c

Related

Gremlin: Return new edges created in a query without saving them (equivalent to APOC vRelationship)

I have a graph with two types of nodes: Persons and Houses. In this graph, persons can sell houses (SELLS relationship), and houses are bought by persons (IS_BOUGHT_BY relationship). This could be represented as the following diagram:
(Person_1)-[:SELLS]->(House_1)-[:IS_BOUGHT_BY]->(Person_2)
A basic example of this diagram can be created in Neo4j by running:
CREATE(Person_1: Person {name:'Person 1'})
CREATE(House_1: House {name:'House 1', deal: 10238})
CREATE(Person_2: Person {name:'Person 2'})
CREATE
(Person_1)-[:SELLS]->(House_1),
(House_1)-[:IS_BOUGHT_BY]->(Person_2)
or can be created in Gremlin by executing:
g.
addV('Person').property('name', 'Person 1').as('p1').
addV('House').property('name', 'House 1').property('deal', 10238).as('h1').
addV('Person').property('name', 'Person 1').as('p2').
addE('SELLS').from('p1').to('h1').
addE('IS_BOUGHT_BY').from('h1').to('p2')
I want to make a query that returns these Person nodes connected with a fake edge called SELLS_HOUSE_TO without saving this relationship in the database. Also this SELLS_HOUSE_TO relationship must have as deal property the deal id of the house sold by Person 1 and bought by Person 2. In other words, I want the output of the query to follow the following diagram:
(Person_1)-[:SELLS_HOUSE_TO {deal: house_1_deal}]->(Person_2)
where id_deal is the deal property of the House_1 node, which connects Person_1 and Person_2 through the SELLS and IS_BOUGHT_BY relationships respectively.
This query can be easily done in Neo4j by using the vRelationship function provided by the APOC library:
MATCH (p1: Person)-[r1:SELLS]->(h1: House)-[r2:BUYS]->(p2: Person)
CALL apoc.create.vRelationship(p1, 'SELLS_HOUSE_TO', {deal: h1.deal}, p2) YIELD rel
RETURN p1, rel, p2
It is possible to do something similar in Gremlin without involving storing the edges in the database at some step?
Currently, Gremlin, outside of perhaps using in-line code (closure/lambda), has no way to inject virtual edges into a query result. This might be a good feature request to open as a Jira ticket for Apache Tinkerpop at this location.
As a short term solution, I think the best you can do is to create the edges for the needs of a visualization and perhaps give them a unique property key and value something like "virtual":true and to delete such edges when no longer needed.

Merge nodes with different labels into new node with both labels

I have a Neo4J database with a bunch of employee and consultant nodes, with a relationship consults pointing from a consultant to an employee node. A consultant can consult many employees and an employee can have multiple consultants.
My issue is that some (not all!) of the consultants are employees as well. How do I go about merging nodes to have two labels to specify those consultants that are employees?
I exported my data from Postgres and imported it to Neo so I have a bunch of nodes like the examples below:
The name field on all the nodes is unique.
Is there a way to match nodes with the same name, create a new node with the new title, and delete the old nodes?
(c:Consultant {name:“Consultant1”})
(e:Employee {name:“Consultant1"})
Desired fix:
(p:Consultant:Employee {name:“Consultant1”)
The APOC procedure apoc.refactor.mergeNodes should work for your use case.
It merges multiple nodes from a list into the first node, and also merges all their relationships as well.

Linking nodes of a particular type to each other sequentially based on a node of another type

I want to link all nodes (of a type) associated with a node (different from previous nodes) to each other. I'll explain this with the help of a diagram. Given below is a dummy representation of a graph that I have created:-
COMMAND:
// Movies are unique values in the dataset.
LOAD CSV WITH HEADERS FROM "actors_movies.csv" AS dataset
CREATE (m:Movie{movie:dataset.name})
MERGE (a:Actor{name:dataset.actor})
MERGE (a)-[:ACTED{year:dataset.year}]->(m)
I want my graph to look like the following where if I query an actor, I should be able to traverse all the movies that they've acted in in a series:
I request for a query to create a graph mentioned above.
Okay, if you only need this for the graphical results, on a per-query per-actor basis, then you may be able to use virtual relationships via APOC Procedures. This will let you create fake virtual relationships that do not actually exist in the graph, but can be visualized in the graph result view. Keep in mind these only last for the duration of the query, they will not be saved to the graph, you'll need to create the virtual relationships with each query where you want to view them.
Here's an example which works for the movies graph (from :play movies in the neo4j browser):
MATCH (k:Person{name:'Keanu Reeves'})-[:ACTED_IN]->(m:Movie)
WITH k, m
ORDER BY m.released ASC
WITH k, apoc.coll.pairsMin(collect(m)) as pairs // list of pairs of adjacent nodes
UNWIND pairs as pair
CALL apoc.create.vRelationship(pair[0], 'NEXT_MOVIE', {year:pair[1].released}, pair[1]) YIELD rel
RETURN k, pair[0] as m1, pair[1] as m2, rel
Keep in mind that if you actually want to have these saved in the graph, you're going to need a path through these movies per actor, so the relationships you create would need to have something like an actorId property, that way when you need to MATCH to the path of movies for an actor you would need to make sure all :NEXT_MOVIE relationships would need to have that actor's id.
That's the only way you could possibly do this in a sane way, otherwise you wouldn't know which relationships to traverse since you need to have the context of which relationship belongs to which actor.

Display a single relationship type Cypher

How can I display neo4j nodes and a unique relationship type linking them?
I have a Neo4j graph, the nodes are linked with multiple relationship types (DODAG, BE, etc..) and I want to display the nodes linked with a specific relationship type without displaying the other relationship links.
When I run
MATCH p=()-[r:DODAG]->() RETURN p
I get the nodes linked by the DODAG relationship type, but the graph also displays the other relationships that link these nodes (BE, etc..)
How could I return the same result, but without the other relationships?
Thank you!
Instead of returning path, return those specific nodes and relationship only:
MATCH (a)-[rel:DODAG]->(b)
RETURN a, rel, b

Searching nodes and properties of nodes

I am trying to create a search function for my meetup app which uses Neo4j as the database. Is there a way to search both nodes (Topic, Department, and Title, getting the people that are attached to them) and properties of nodes (first name, last name, username, bio).
The Person node has a relationship to a Title node (via IS_TITLED) and a relationship to Department node (via EMPLOYED_BY) and relationship to Topic nodes (via INTEREST_OF or SKILL_OF)
Also I would like to make sure that the results are distinct for each person so if the person puts in the title of a person and a department and it gets 2 matches, then the person only returns once.
Your question is very broad, but here is an example query that:
Finds all people employed by the Finance department and have the titled "Clerk".
Ensures they are distinct people.
Returns their first name, last name, username, and bio.
MATCH (d:Department)<-[:EMPLOYED_BY]-(p:Person)-[:IS_TITLED]->(t:Title)
WHERE d.name = "Finance" AND t.name = "Clerk"
WITH DISTINCT p
RETURN p.fname AS firstname, p.lname AS lastname, p.username AS username, p.bio AS bio;
Actually I wasn't looking for an entire application. My final solution was to add,update, and remove documents in ElasticSearch when my nodes where added, update, and removed. Then I use ElasticSearch to find results and return a list of node id's. Then I wrote my Cypher query to pull information using IN for the returned id's to produce the results. It seems to work perfectly. Since I couldn't find an integrated solution for syncing Neo4j and ElasticSearch, I use both libraries in my application and just perform the appropriate action on ElasticSearch when the nodes were effected.

Resources