cancel
Showing results for 
Search instead for 
Did you mean: 

How to find what does NOT satisfy a relationship

cassiodorus
Node Link

Application visualizes drug-drug interactions. Drug names are in node Names. Some drugs are members of classes (one and only one). Class is in node DrugClass, related to the drugs in Names by relationship DRUG_CLASS. Interactions between drugs are in relationship INTERACTION, between two nodes in Names. Not really much to the database structure, although a few million rows of drug-drug interactions, and a few thousand drugs.

This query works just the way it should, retrieving a graph of interactions of Levothyroxine with the drugs in the list of classes:

MATCH (d1:DrugClass)-[rd:DRUG_CLASS]->(n1:Names)<-[ri:INTERACTION]-(n2:Names)
WHERE d1.drugClass IN ['CCBnonDihydropyridines','Statins','AngiotensinIIreceptorBlockers'] AND
  n2.name='Levothyroxine'
  RETURN *
But ... I know that there are some drugs in those drug classes that do NOT interact with Levothyroxine. There should be some simple way to query the graph for those drugs, analogously to the above graph. I have tried (and tried ...) and cannot figure out any proper use of NOT. I have achieved a working but unsatisfactory solution via python and py2neo that I won't even discuss it because it is so ugly. I would greatly appreciate some kind suggestions.
1 ACCEPTED SOLUTION

glilienfield
Ninja
Ninja

I think this should give you the drugs that interact with the Levothyroxine and are in the specified drug classes.  Do you really need d1, rd, and ri (in your original query)? 

WITH ['CCBnonDihydropyridines','Statins','AngiotensinIIreceptorBlockers'] as drugClasses
MATCH (n2:Names{name: 'Levothyroxine'})
MATCH (d1:DrugClass)-[rd:DRUG_CLASS]->(n1:Names)
WHERE d1.drugClass IN drugClasses 
WITH  n1, n2, {DrugClass: d1, DRUG_CLASS: rd} as drugClassInfo
WHERE EXISTS ((n1)<-[:INTERACTION]-(n2))
RETURN n1, drugClassInfo

This modified version, should give you the opposite, which is the drugs that do not interact with Levothyroxine and are in the specified drug classes:

WITH ['CCBnonDihydropyridines','Statins','AngiotensinIIreceptorBlockers'] as drugClasses
MATCH (n2:Names{name: 'Levothyroxine'})
MATCH (d1:DrugClass)-[rd:DRUG_CLASS]->(n1:Names)
WHERE d1.drugClass IN drugClasses 
WITH  n1, n2, {DrugClass: d1, DRUG_CLASS: rd} as drugClassInfo
WHERE NOT EXISTS ((n1)<-[:INTERACTION]-(n2))
RETURN n1, drugClassInfo

View solution in original post

6 REPLIES 6

ameyasoft
Graph Maven

Try this:

//Collect all drugs in the selected drug classes.....

MATCH (d1:DrugClass)-[rd:DRUG_CLASS]->(n1:Names)
WHERE d1.drugClass IN ['CCBnonDihydropyridines','Statins','AngiotensinIIreceptorBlockers']

WITH d1, COLLECT(distinct n1.name) as drugs

//Get the drugs that interact with Levothyroxine....

MATCH (n1:Names)<-[ri:INTERACTION]-(n2:Names)
WHERE n1.name in drugs AND n2.name='Levothyroxine'

//Get the drugs that do not inteact with Levothyroxine....

MATCH (n1:Names)<-[ri:INTERACTION]-(n2:Names)
WHERE n1.name in drugs AND n2.name <>'Levothyroxine'

//Result........

RETURN distinct n1.name

Hi ameyasoft, thank you very much for your time and effort. I think your method is not quite correct. The 'get drugs not interacting with' returns all the interactions amongst all the 'drugs', which is a superset based on 'drugs'. Your method is an improvement over my attempts.

I think your first step is on target, returning all the drugs in the named classes. Next should be your correct second step. But the correct third step would be the (list) difference between what was returned by the first and second step. So you are 2/3 of the way there. I can handle that via python (py2neo) and I am sure there is a way in native neo4j (for instance, APOC provides for list differences). My particular problem is that I don't see how to 'remember' the returns from steps 1 and 2 unless I use python. Have you got the time to help me with this?

ameyasoft
Graph Maven

Try this:

//Get the drugs that interact with Levothyroxine....

MATCH (n1:Names)<-[ri:INTERACTION]-(n2:Names)
WHERE n1.name in drugs AND n2.name='Levothyroxine'

WITH drugs, COLLECT(distinct n1.name) as levo

// Subtract the drugs interacted with levo......get non-interacting drugs....

WITH drug, apoc.coll.subtract(drug, levo) as nolevo

RETURN drug, nolevo, size(nolevo) as cnt

My sincere thanks. I think the glilienfield solution is simpler. 

I am delighted to see the neo4j community respond with such help.

glilienfield
Ninja
Ninja

I think this should give you the drugs that interact with the Levothyroxine and are in the specified drug classes.  Do you really need d1, rd, and ri (in your original query)? 

WITH ['CCBnonDihydropyridines','Statins','AngiotensinIIreceptorBlockers'] as drugClasses
MATCH (n2:Names{name: 'Levothyroxine'})
MATCH (d1:DrugClass)-[rd:DRUG_CLASS]->(n1:Names)
WHERE d1.drugClass IN drugClasses 
WITH  n1, n2, {DrugClass: d1, DRUG_CLASS: rd} as drugClassInfo
WHERE EXISTS ((n1)<-[:INTERACTION]-(n2))
RETURN n1, drugClassInfo

This modified version, should give you the opposite, which is the drugs that do not interact with Levothyroxine and are in the specified drug classes:

WITH ['CCBnonDihydropyridines','Statins','AngiotensinIIreceptorBlockers'] as drugClasses
MATCH (n2:Names{name: 'Levothyroxine'})
MATCH (d1:DrugClass)-[rd:DRUG_CLASS]->(n1:Names)
WHERE d1.drugClass IN drugClasses 
WITH  n1, n2, {DrugClass: d1, DRUG_CLASS: rd} as drugClassInfo
WHERE NOT EXISTS ((n1)<-[:INTERACTION]-(n2))
RETURN n1, drugClassInfo

I never even thought of starting with WITH! A real eye-opener.

Thank you very much.

Nodes 2022
Nodes
NODES 2022, Neo4j Online Education Summit

On November 16 and 17 for 24 hours across all timezones, you’ll learn about best practices for beginners and experts alike.