cypher match query merge result set - neo4j

I'm newer in CQL anyone help me to solve query to find list of followers with a flag if i also follow him. i'm trying like this way
MATCH (n:users_master)-[r:FOLLOW]->(m:users_master)
OPTIONAL MATCH (n:users_master)<-[r2:FOLLOW]-(m:users_master)
CASE when EXISTS(r2) THEN n.flag= 1 ELSE n.flag=0 END
where id(m)=35
RETURN n
notice here i'd also like to add a virtual property flag in result set LIKE {"updated_at":"12/26/2016, 3:45:38 PM",
"created_on":"12/26/2016, 3:45:38 PM",
"last_name":"john",
"first_name":"john",
"email":"new#test",
"facebook_id":"12341",
"status":"Active",
"id":35
"flag":1
}

The EXISTS() function can be used to check for the existence of a pattern, and in your case can replace your OPTIONAL MATCH.
Also, variables in your patterns aren't needed if you aren't going to be using them, so you shouldn't need them on your relationships at all.
MATCH (n:users_master)-[:FOLLOW]->(m:users_master)
WHERE id(m)=35
RETURN n, EXISTS( (n)<-[:FOLLOW]-(m) ) as flag
'flag' will be a separate column with a boolean on whether or not the follow is reciprocal.
As far as adding a 'virtual property', in Neo4j 3.1+, you can use Map Projection to add custom values to the map projection of returned nodes.
You could use this query with map projection to include the flag in the return of node properties:
MATCH (n:users_master)-[:FOLLOW]->(m:users_master)
WHERE id(m)=35
RETURN n {.*, flag: EXISTS( (n)<-[:FOLLOW]-(m) ) }
EDIT
The map projection used in the query above was introduced and only works in Neo4j 3.1.x and up.
For versions 3.0.x, I don't believe there are many options for extracting all node properties to a map and adding a new value to that map before returning (SET clause is reserved for nodes, not maps).
You may need to install APOC procedures for a workaround, as it provides several helper procedures and functions, including map operations.
This should work after the relevant version of APOC is added to your Neo4j instance:
MATCH (n:users_master)-[:FOLLOW]->(m:users_master)
WHERE id(m)=35
RETURN apoc.map.setKey(properties(n), 'flag', EXISTS( (n)<-[:FOLLOW]-(m) )) as n

Related

Neo4j Subgraph Projection using a string inside string query

Working on a project, I was trying to reduce the number of variables to make something easier to visualize for creating embeddings and checking if they work.
I realized there was a projection and a subprojection. I can definitely create a new neo4j graph, but that seems like a slow solution.
so just following the tutorial, they have
CALL gds.graph.project(
'apps_undir',
['App', 'Genre']
{Genre_Category: {orientation: 'UNDIRECTED'}}
)
then something like
CALL gds.beta.graph.project.subgraph(
'subapps',
'apps_undir',
"n:App OR (n:Genre AND n.name = 'Action' OR n.name = 'RPG')",
'*'
)
I realize this isn't python, but it's the idea I'm trying to express. With the string query as 'n:App OR (n:Genre AND n.name = Action OR n.name = RPG)' I get the error:
Failed to invoke procedure gds.beta.graph.project.subgraph: Caused by: org.neo4j.gds.beta.filter.expression.SemanticErrors: Semantic errors while parsing expression:
Invalid variable `Action`. Only `n` is allowed for nodes
Invalid variable `RPG`. Only `n` is allowed for nodes
Unknown property `name`.
Unknown property `name`.
the error produced is
"Neo.ClientError.Statement.SyntaxError
Invalid input 'subgraph': expected"
As subgraph is only in beta functionality isn't great, but all node names apparently need to be n,
for the actual subgraph, and performing an embedding on that
if it helps, this was taken from a steam database scrape from 2016 and a couple csv values are below:
appid;Genre
8890;RPG
8890;Strategy
10530;Action
10530;RPG
15540;Indie
15560;Action
15620;Strategy
There are a couple of problems with your workflow. When you project a graph in GDS with the following command, it doesn't include any node properties by default.
CALL gds.graph.project(
'apps_undir',
['App', 'Genre']
{Genre_Category: {orientation: 'UNDIRECTED'}}
)
There are ways to include node properties in the graph projections, however string format is not supported. Therefore, you cannot project the name property which appears to be a string. To achieve what you want to do you should probably use Cypher projection.
CALL gds.graph.project.cypher('subapps',
'MATCH (n) WHERE n:App OR (n:Genre AND n.name IN ["Action", "RPG"]) RETURN id(n) AS id',
'MATCH (s)-[:Genre_Category]-(t) RETURN id(s) AS source, id(t) AS target',
{validateRelationship:false})
A couple of pointers for Cypher projection. To define the relationships I have used (s)-[:Genre_Category]-(t) pattern. Notice the lack of relationship direction. By avoiding the relationship direction definition, the relationships will be projected as "undirected". You need to include the validateRelationship parameter since you perform node filtering in the node projection, but not in the relationship projection.

Neo4J Matching Nodes Based on Multiple Relationships

I had another thread about this where someone suggested to do
MATCH (p:Person {person_id: '123'})
WHERE ANY(x IN $names WHERE
EXISTS((p)-[:BELONGS]-(:Face)-[:CORRESPONDS]-(:Image)-[:HAS_ACCESS_TO]-(:Dias {group_name: x})))
MATCH path=(p)-[:ASSOCIATED_WITH]-(:Person)
RETURN path
This does what I need it to, returns nodes that fit the criteria without returning the relationships, but now I need to include another param that is a list.
....(:Dias {group_name: x, second_name: y}))
I'm unsure of the syntax.. here's what I tried
WHERE ANY(x IN $names and y IN $names_2 WHERE..
this gives me a syntax error :/
Since the ANY() function can only iterate over a single list, it would be difficult to continue to use that for iteration over 2 lists (but still possible, if you create a single list with all possible x/y combinations) AND also be efficient (since each combination would be tested separately).
However, the new existenial subquery synatx introduced in neo4j 4.0 will be very helpful for this use case (I assume the 2 lists are passed as the parameters names1 and names2):
MATCH (p:Person {person_id: '123'})
WHERE EXISTS {
MATCH (p)-[:BELONGS]-(:Face)-[:CORRESPONDS]-(:Image)-[:HAS_ACCESS_TO]-(d:Dias)
WHERE d.group_name IN $names1 AND d.second_name IN $names2
}
MATCH path=(p)-[:ASSOCIATED_WITH]-(:Person)
RETURN path
By the way, here are some more tips:
If it is possible to specify the direction of each relationship in your query, that would help to speed up the query.
If it is possible to remove any node labels from a (sub)query and still get the same results, that would also be faster. There is an exception, though: if the (sub)query has no variables that are already bound to a value, then you would normally want to specify the node label for the one node that would be used to kick off that (sub)query (you can do a PROFILE to see which node that would be).

Cypher query returning null values even when the pattern is available in database

Is something wrong with this cypher query
MATCH (owner:SidNode)<-[:OWNED_BY]-(acl:AclNode)-[:SECURES]->(class:ClassNode)
OPTIONAL MATCH (acl)<-[:COMPOSES]-(ace:AceNode)-[:AUTHORIZES]->(sid:SidNode)
WITH acl, ace, owner, sid, class
WHERE (acl.objectIdIdentity = {objectIdIdentity1} AND class.className = {className1})
RETURN
owner.principal AS aclPrincipal,
owner.sid AS aclSid,
acl.objectIdIdentity AS objectIdIdentity,
ace.aceOrder AS aceOrder,
ID(acl) AS aclId,
acl.parentObject AS parentObject,
acl.entriesInheriting AS entriesInheriting,
ID(ace) AS aceId, ace.mask AS mask,
ace.granting AS granting,
ace.auditSuccess AS auditSuccess,
ace.auditFailure AS auditFailure,
sid.principal AS acePrincipal,
sid.sid AS aceSid,
class.className AS className
ORDER BY acl.objectIdIdentity ASC, ace.aceOrder ASC
It is returning null values for ace nodes even though there are multiple nodes available in graph db.
But some times it is returning proper values like 4 rows if there are 4 ace nodes in db.
code i am writing is about spring security acl
reference link:
https://github.com/shazin/spring-security-acl-neo4j/blob/master/src/main/java/org/springframework/security/acls/neo4j/Neo4jLookupStrategy.java
Please suggest modifications.
Your problem comes from OPTIONAL MATCH, according to Neo4j's documentation, OPTIONAL MATCH returns NULLif the property or the element is not found.
You are getting NULL values because of this. If your acl node doesn't have any ace node related to him, the node will be replaced with NULL
You bind the ace nodes in an optional match. When that optional match fails to match something, ace will be null.
If you think the optional match ought to be successful in cases when it is not, maybe you could provide an example. A good way to do so is to create a small sample graph at http://console.neo4j.org
The conditions in your WHERE clause look like they belong with your MATCH clause. You might want to move the WHERE clause up and you can then remove the WITH altogether. It won't affect nulls, but it will make your query more efficient and more readable. (Also, you don't need parentheses in your WHERE clause.)
MATCH (owner:SidNode)<-[:OWNED_BY]-(acl:AclNode)-[:SECURES]->(class:ClassNode)
WHERE acl.objectIdIdentity = {objectIdIdentity1} AND class.className = {className1}
OPTIONAL MATCH (acl)<-[:COMPOSES]-(ace:AceNode)-[:AUTHORIZES]->(sid:SidNode)
RETURN ...

Single Cypher query to choose between 2 different paths

I have the following scenario:
At some point in my path (in a node that lies a few links away from my start node),
I have the possibility of going down one path or another, for example:
If S is my startnode,
S-[]->..->(B)-[first:FIRST_WAY]->(...) ,
and
S-[]->..->(B)-[second:SECOND_WAY]->(...)
At the junction point, I will need to go down one path only (first or second)
Ideally, I would like to follow and include results from the second relationship, only if the first one is not present (regardless of what exists afterwards).
Is this possible with Cypher 1.9.7, in a single query?
One way would be to an optional match to match the patterns separately. Example:
MATCH (n:Object) OPTIONAL MATCH (n)-[r1:FIRST_WAY]->(:Object)-->(f1:Object) OPTIONAL MATCH (n)-[r2:SECOND_WAY]->()-->(f2:Object) RETURN coalesce(f2, f1)
This query will match both conditionally and the coalesce function will return the first result which is not null.
AFAIK, OPTIONAL_MATCH was introduced in 2.0 so you can't use that clause in 1.9, but there is an alternate syntax:
CYPHER 1.9 START n=node(*) MATCH (n)-[r1?:FIRST_WAY]->()-->(f1), (n)-[r2?:SECOND_WAY]->()-->(f2) RETURN coalesce(f2, f1)
I'm sure there are other ways to do this, probably using the OR operator for relationship matching, i.e. ()-[r:FIRST_WAY|SECOND_WAY]->(), and then examining the patterns matched to discard some of the result paths based on the relationship type.

Return node if relationship is not present

I'm trying to create a query using cypher that will "Find" missing ingredients that a chef might have, My graph is set up like so:
(ingredient_value)-[:is_part_of]->(ingredient)
(ingredient) would have a key/value of name="dye colors". (ingredient_value) could have a key/value of value="red" and "is part of" the (ingredient, name="dye colors").
(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)
I'm using this query to get all the ingredients, but not their actual values, that a recipe requires, but I would like the return only the ingredients that the chef does not have, instead of all the ingredients each recipe requires. I tried
(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)<-[:has_ingredient*0..0]-chef
but this returned nothing.
Is this something that can be accomplished by cypher/neo4j or is this something that is best handled by returning all ingredients and sorted through them myself?
Bonus: Also is there a way to use cypher to match all values that a chef has to all values that a recipe requires. So far I've only returned all partial matches that are returned by a chef-[:has_value]->ingredient_value<-[:requires_value]-recipe and aggregating the results myself.
Update 01/10/2013:
Came across this in the Neo4j 2.0 reference:
Try not to use optional relationships.
Above all,
don’t use them like this:
MATCH a-[r?:LOVES]->() WHERE r IS NULL where you just make sure that they don’t exist.
Instead do this like so:
MATCH (a) WHERE NOT (a)-[:LOVES]->()
Using cypher for checking if relationship doesn't exist:
...
MATCH source-[r?:someType]-target
WHERE r is null
RETURN source
The ? mark makes the relationship optional.
OR
In neo4j 2 do:
...
OPTIONAL MATCH source-[r:someType]-target
WHERE r is null
RETURN source
Now you can check for non-existing (null) relationship.
For fetching nodes with not any relationship
This is the good option to check relationship is exist or not
MATCH (player)
WHERE NOT(player)-[:played]->()
RETURN player
You can also check multiple conditions for this
It will return all nodes, which not having "played" Or "notPlayed" Relationship.
MATCH (player)
WHERE NOT (player)-[:played|notPlayed]->()
RETURN player
To fetch nodes which not having any realtionship
MATCH (player)
WHERE NOT (player)-[r]-()
RETURN player
It will check node not having any incoming/outgoing relationship.
If you need "conditional exclude" semantic, you can achieve it this way.
As of neo4j 2.2.1, you can use OPTIONAL MATCH clause and filter out the unmatched(NULL) nodes.
It is also important to use WITH clause between the OPTIONAL MATCH and WHERE clauses, so that the first WHERE defines a condition for the optional match and the second WHERE behaves like a filter.
Assuming we have 2 types of nodes: Person and Communication. If I want to get all Persons which have never communicated by the telephone, but may have communicated other ways, I would make this query:
MATCH (p: Person)
OPTIONAL MATCH p--(c: Communication)
WHERE c.way = 'telephone'
WITH p, c
WHERE c IS NULL
RETURN p
The match pattern will match all Persons with their communications where c will be NULL for non-telephone Communications. Then the filter(WHERE after WITH) will filter out telephone Communications leaving all others.
References:
http://neo4j.com/docs/stable/query-optional-match.html#_introduction_3
http://java.dzone.com/articles/new-neo4j-optional
I wrote a gist showing how this can be done quite naturally using Cypher 2.0
http://gist.neo4j.org/?9171581
The key point is to use optional match to available ingredients and then compare to filter for missing (null) ingredients or ingredients with the wrong value.
Note that the notion is declarative and doesn't need to describe an algorithm, you just write down what you need.
The last query should be:
START chef = node(..)
MATCH (chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)
WHERE (ingredient)<-[:has_ingredient]-chef
RETURN ingredient
This pattern: (ingredient)<-[:has_ingredient*0..0]-chef
Is the reason it didn't return anything. *0..0 means that the length of the relationships must be zero, which means that ingredient and chef must be the same node, which they are not.
I completed this task using gremlin. I did
x=[]
g.idx('Chef')[[name:'chef1']].as('chef')
.out('has_ingredient').as('alreadyHas').aggregate(x).back('chef')
.out('has_value').as('values')
.in('requires_value').as('recipes')
.out('requires_ingredient').as('ingredients').except(x).path()
This returned the paths of all the missing ingredients. I was unable to formulate this in the cypher language, at least for version 1.7.
For new versions of Neo4j, you'll have this error:
MATCH (ingredient:Ingredient)
WHERE NOT (:Chef)-[:HAS_INGREDIENT]->(ingredient)
RETURN * LIMIT 100;
This feature is deprecated and will be removed in future versions.
Coercion of list to boolean is deprecated. Please consider using NOT isEmpty(...) instead.
To fix it:
MATCH (ingredient:Ingredient)
WHERE NOT EXISTS((:Chef)-[:HAS_INGREDIENT]->(ingredient))
RETURN * LIMIT 100;

Resources