Check if node exists and use the result as a condition

Sorry, to ask this question for the 100th time, but none of the previous posts was similar to my problem: I just want to get back TRUE or FALSE if a node with a certain label and a certain value of a property exists.

(u:User {user_id: 1} => TRUE / FALSE

All other posts where about MERGE and so on, but I don't want to create anything, I want to use it as a condition in an apoc.do.when-function.

This is tricky! the exists() function doesn't work the way I had hoped... and you can't compare the MATCH results with null.

but this works:

MATCH (u:User {user_id: 1})
WITH count(*) as count
CALL apoc.when (count > 0, // won't work so well if user_id isn't unique...
"RETURN true AS bool",     // one or more users with user_id = 1
"RETURN false AS bool",    // no users with user_id = 1
{count:count}
) YIELD value
return value.bool

There may be a better way to do this, but I don't know..

Remember apoc.do.when is for when you want to change the DB, apoc.when is if you are just reading.

[added] a better solution is further towards the end of this thread!

Thanks a lot, I have tried it with exists() and comparing with NULL - and as you said without any success. I did not come to the conclusion to try it with count().

I basically don't understand why Cypher (or at least APOC) does not provide a function for that.

I don't know either... The Cypher language could evolve to do this, but it's still a relatively young language, so maybe it will get extended.

1 Like

Hi @janezic ,

hope this works ... try this CASE expression

merge (p:Person{name:"Dominic",db:"Neo4j"});
Added 1 label, created 1 node, set 2 properties, completed after 6 ms.

merge (p:Person{name:"Kumar"});
Added 1 label, created 1 node, set 1 property, completed after 6 ms.


match (n) return (n)
╒═══════════════════════════════╕
β”‚"n"                            β”‚
β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
β”‚{"name":"Dominic","db":"Neo4j"}β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚{"name":"Kumar"}               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

MATCH (p:Person)
RETURN p.name,
CASE
WHEN exists(p.db)  THEN true
ELSE false END AS db_property_status;

╒═════════╀════════════════════╕
β”‚"p.name" β”‚"db_property_status"β”‚
β•žβ•β•β•β•β•β•β•β•β•β•ͺ════════════════════║
β”‚"Dominic"β”‚true                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚"Kumar"  β”‚false               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
1 Like

Sorry, this solves different question: whether a property exists, not whether a node with a specific value exists.

@clem , please, visit the CASE statement documentation -> Expressions - Cypher Manual. It can be simply changed to condition. CASE statements exists from RDBMS too.

@janezic



match (n) return (n)
╒═══════════════════════════════╕
β”‚"n"                            β”‚
β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘
β”‚{"name":"Dominic","db":"Neo4j"}β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚{"name":"Kumar"}               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

MATCH (p:Person)
RETURN p.name,
CASE
WHEN p.db="Neo4j"  THEN true
ELSE false END AS db_property_status;

╒═════════╀════════════════════╕
β”‚"p.name" β”‚"db_property_status"β”‚
β•žβ•β•β•β•β•β•β•β•β•β•ͺ════════════════════║
β”‚"Dominic"β”‚true                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚"Kumar"  β”‚false               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Good Morning,
thank you, but no, this is basically not exactly what I was looking for, because it gives me all users with all their email-addresses with a additional column true/false.

Of course you could filter it again, but this is a very expensive query.

I just want to know, if a node with a certain value of a property exists.

Wow, at the beginning I was pfff that's super easy...hoo no that's not indeed.
Funny, I like challenge, I didn't solve it yet but I see a OPTIONAL MATCH clause as an work around solution.

And by the way, null laws of neo4j implies that null is not equal to null since null is nothing not a value and then since we don't know what it is you can't compare something you don't know with something you don't know.

OPTIONAL MATCH (n:Label {property:value})
RETURN exists(n.property) AS Predicate

It will give you one row with true or null as output, it's not exactly the end result wanted but it's the closer one I got for now.

1 Like

If you add IS NOT null then you will get a true when property has the value /false when the property doesn't have the value.

I hadn't thought of using OPTIONAL. Clever! Also you don't need exists(); you can just test n for null

OPTIONAL MATCH (n:User{user_id:1})
RETURN n IS NOT NULL AS Predicate

(note exists(n) doesn't work.)

This is a good example of using OPTIONAL.

[added] Without OPTIONAL and if User with user_id = 1 doesn't exist, then the MATCH returns no records which is different than returning null. Subtle!

Also reminder for Cypher beginners: the test n <> null is incorrect for testing null/non-null. This is correct: n IS NOT null

3 Likes

Wow, the solution is so simple and so hard to find on the other hand.

THANK YOU!!!

The key here is this fact:

MATCH return nothing if he finds nothing
OPTIONAL MATCH always return at least null

Thanks clem I was looking for an operator for the null or something like that.

I didn't know you could use a lonely optional match :thinking:

We did it, next challenge.

1 Like

I added a suggestion to the documentation for OPTIONAL MATCH.

This is a great example!

I've learned a lot! Thanks for showing us OPTIONAL MATCH. I hadn't quite appreciated what it could do.

I just found this thread.

I have some comments about the proposed solution:

OPTIONAL MATCH (n:User{user_id:1})
RETURN n IS NOT NULL AS Predicate

The above solution is not appropriate if the OPTIONAL MATCH can find multiple (N) matches. That is because in that case it would: (1) do the work to find all N matches and not stop after finding just the first one, and (2) it would return N Predicate values (all true).

Here is one simple way to fix both issues:

OPTIONAL MATCH (n:User{user_id:1})
WITH n LIMIT 1
RETURN n IS NOT NULL AS Predicate

There are other solutions as well, including using the EXISTS() function properly.

The EXISTS function must be passed a pattern that has a relationship. Here is a tricky way to use a 0-length variable relationship pattern with EXISTS to match a node (that does not need to have a relationship). It is, unfortunately, hard to read; but it does work.

RETURN EXISTS((:User{user_id:1})-[*0]-()) AS Predicate

Also, neo4j 5.3 added the EXISTS subquery, which is a little easier to read:

RETURN EXISTS { (:User{user_id:1}) } AS Predicate