Matching Nodes that have Array properties containing specific values - neo4j

I have node of type User which has an array property called 'emails' that contains an array of emails (strings). I am trying to write a cypher query that can be used to look up nodes that match a specific email address (in other words - given an email address, I want to look up all nodes that contain that email address within their 'emails' property.
MATCH(u:User) WHERE 'abc#gmail.com' IN u.emails RETURN u;
However, the above query returns nothing. I have confirmed that I do have a node that contains the property, see below:
u
id ed2ac321-60e3-4765-95b6-b097726454bf
emails ["abc#gmail.com"]
Not sure what I'm missing here.
EDIT: I found the issue, thanks to the question posted by stdob. I was creating the array in correctly - I was using quotes like this:
CREATE (u:User {id: 'ed2ac321-60e3-4765-95b6-b097726454bf', emails: '["abc#gmail.com"]'}) RETURN u;
Output:
u
emails ["abc#gmail.com"]
id ed2ac321-60e3-4765-95b6-b097726454bf
This internally was creating a simple string property called emails, not an array. To fix this, I removed the quotes:
CREATE (u:User {id: 'ed2ac321-60e3-4765-95b6-b097726454bf', emails: ["abc#gmail.com"]}) RETURN u;
Output:
u
emails [abc#gmail.com]
id ed2ac321-60e3-4765-95b6-b097726454bf
There's a subtle difference in the way the neo4j web interface displays the output of the above two statements, but worth a lot!

Related

How to filter out non-null path between nodes in Neo4J/Cypher

My current graph monitors board members at a company through time.
However, I'm only interested in currently employed directors. This can be observed because director nodes connect to company nodes through an employment path which includes an end date (r.to) when the director is no longer employed at the firm. If he is currently employed, there will be no end date(null as per below picture). Therefore, I would like to filter the path not containing an end date. I am not sure if the value is an empty string, a null value, or other types so I've been trying different ways without much success. Thanks for any tips!
Current formula
MATCH (c2:Company)-[r2:MANAGED]-(d:Director)-[r:MANAGED]-(c:Company {ticker:'COMS'})
WHERE r.to Is null
RETURN c,d,c2
Unless the response from the Neo4j browser was edited, it looks like the value of r.to is not null or empty, but the string None.
This query will help verify if this is the case:
MATCH (d:Director)-[r:MANAGED]-(c:Company {ticker:'COMS'})
RETURN DISTINCT r.to ORDER by r.to DESC
Absence of the property will show a null in the tabular response. Any other value is a real value of that property. If None shows up, then your query would be
MATCH (c2:Company)-[r2:MANAGED]-(d:Director)-[r:MANAGED]-(c:Company {ticker:'COMS'})
WHERE r.to="None"
RETURN c,d,c2

Not able to create a node with special characters "-" in neo4j

I am trying to create a node in neo4j(version 3.2.3). Below is the cypher query,
MERGE (`source-real-address`:SOURCE {Source:{`source-real-address`}})
I found in forums to create a node with special characters we should use
backticks `
in the query. But I couldn't able to create a node with backticks. No error were thrown in the logs.
Could you please help me to resolve this?
Please correct me if I am doing anything wrong in the cypher query. I am started
to understand neo4j cypher query language.
Note:- I am sending data to neo4j from graylog with the help of neo4j output plugin. I could able to create node without special character fields.
The syntax {Source:{`source-real-address`}}) means that you are trying to use a param named source-real-address as the value of the property Source. If this is your goal, you can set a param in the Neo4j Browser for test purposes with :params {"source-real-address":"Some value"}. If not, you can remove the extra { and } in the value and use "" instead of backticks, like this:
MERGE (source-real-address:SOURCE {Source:"source-real-address"})
Remeber that the value of a property should be Boolean, Integer, Float or String.
In Cypher backticks are used to create relationships, labels and variable names with special chars (not for property values).
Use the CREATE command to create Node with special characters
see this also: https://neo4j.com/docs/cypher-manual/current/syntax/naming/

Any way to whitelist or blacklist properties returned from a node?

Nodes returned in neo4j seem to be special, in that they output as JSON objects, and they don't appear at all if they're null.
An example:
I have a :Person object, and they can have 0 or more :Friend relationships to another :Person.
Let's say that a :Person has the following properties: ID, firstName, lastName, sensitiveThing.
sensitiveThing is a property that might be used by our system, or could be personally accessible to the user themselves, but we don't want to return it to any other user.
If I want a query to give me back data of my friends, and friends of those friends, I might use a query like this
MATCH (me:User{ID:777})-[:Friend]-(friend:User)
WITH me, friend
OPTIONAL MATCH (friend)-[:Friend]-(foaf:User)
WHERE me <> foaf
RETURN friend.ID, friend.firstName, friend.lastName, COLLECT(foaf) AS FriendOfAFriend
While this lets me nicely bundle up friends of friends as JSON objects within a JSON array, and correctly emits an empty array if a friend doesn't have any other friends besides me, I don't want to return sensitiveThing with this query.
If I try to replace COLLECT(foaf) with a custom object only including fields I care about, like this:
COLLECT({ID:(foaf.ID), firstName:(foaf.firstName), lastName:(foaf.lastName)})
then I get what I want...until I hit the case where there are no friends of friends. When I was working with nodes before, the object wouldn't even be emitted. But now, I would get something like this returned to me:
[{ID: (null), firstName: (null), lastName: (null)}]
This is obviously not what I want.
Ideally, I'm looking for a way to return a node as before, but whitelist or blacklist properties I want to emit, so I can retain the correct null handling if the node is null (from an optional match)
If I can't have that, then I'd like a way to use a custom object, but not return the object at all if all its fields are null.
Any other workarounds or tips for dealing with optional matches are more than welcome.
You can use apoc.map.removeKeys:
WITH {p1: 1, p2: 2, p3: 3, p4: 4} as node
CALL apoc.map.removeKeys( node, ['p2', 'p4'] ) YIELD value
RETURN value
I've never seen a way to whitelist or blacklist properties in the documentation.
However, you can return your custom object by chaining collect with extract:
MATCH (me:User{ID:777})-[:Friend]-(friend:User)
WITH me, friend
OPTIONAL MATCH (friend)-[:Friend]-(foaf:User)
WHERE me <> foaf
WITH friend, collect(foaf) AS FriendOfAFriend
RETURN friend.ID, friend.firstName, friend.lastName,
extract(foaf in FriendOfAFriend | {ID:(foaf.ID), firstName:(foaf.firstName), lastName:(foaf.lastName)}) AS FriendOfAFriend
collect will return an empty list if there are no friends, extract will keep it that way.

Find path in Neo4j with directed edges

This is my first attempt at Neo4j, please excuse me if I am missing something very trivial.
Here is my problem:
Consider the graph as created in the following Neo4j console example:
http://console.neo4j.org/?id=y13kbv
We have following nodes in this example:
(Person {memberId, memberName, membershipDate})
(Email {value, badFlag})
(AccountNumber {value, badFlag})
We could potentially have more nodes capturing features related to a Person like creditCard, billAddress, shipAddress, etc.
All of these nodes will be the same as Email and AccountNumber nodes:
(creditCard {value, badFlag}), (billAddress {value, badFlag}),etc.
With the graph populated as seen in the Neo4j console example, assume that we add one more Person to the graph as follows:
(p7:Person {memberId:'18' , memberName:'John', membershipDate:'12/2/2015'}),
(email6:Email {value: 'john#gmail.com', badFlag:'false'}),
(a2)-[b13:BELONGS_TO]->(p7),
(email6)-[b14:BELONGS_TO]->(p7)
When we add this new person to the system, the use case is that we have to check if there exists a path from features of the new Person ("email6" and "a2" nodes) to any other node in the system where the "badFlag=true", in this case node (a1 {value:1234, badFlag:true}).
Here, the resultant path would be (email6)-[BELONGS_TO]->(p7)<-[BELONGS_TO]-(a2)-[BELONGS_TO]->(p6)<-[BELONGS_TO]-(email5)-[BELONGS_TO]->(p5)<-[BELONGS_TO]-(a1:{badFlag:true})
I tried something like this:
MATCH (newEmail:Email{value:'john#gmail.com'})-[:BELONGS_TO]->(p7)-[*]-(badPerson)<-[:BELONGS_TO]-(badFeature{badFlag:'true'}) RETURN badPerson, badFeature;
which seems to work when there is only one level of chaining, but it doesn't work when the path could be longer like in the case of Neo4j console example.
I need help with the Cypher query that will help me solve this problem.
I will eventually be doing this operation using Neo4j's Java API using my application. What could be the right way to go about doing this using Java API?
You had a typo in you query. PART_OF should be BELONGS_TO. This should work for you:
MATCH (newEmail:Email {value:'john#gmail.com'})-[:BELONGS_TO]->(p7)-[*]-(badPerson)<-[:BELONGS_TO]-(badFeature {badFlag:'true'})
RETURN badPerson, badFeature;
Aside: You seem to use string values for all properties. I'd replace the string values 'true' and 'false' with the boolean values true and false. Likewise, values that are always numeric should just use integer or float values.

Evaluating similar strings

Person has many addresses. I'm trying to create an address for a person if the JSON response from an API is different from any of the addresses in the db.
I wrote the following, which works with literal use cases; it prevents duplicate addresses:
p = Person.find(1)
unless p.addresses.any? { |i| i.address_1.eql?(#response['addresses'][0]['street'].upcase) }
This works by taking the array, mapping the address object, and calling eql? on the address_ column (street address).
However, if the street address is suffixed with "blvd" or "ln", I want to add that address to the person. I haven't found a method that evaluates two strings for similarities. Is there some method like similar_to? that might help me?

Resources