Cypher query and Ruby on Rails - neo4j

I have a Cypher query like this:
start n=node(*) match n-[:has_comments]->(m) return n,m;
which runs ok.
How can I run this from RoR?
When using Postgres and ActiveModel, in the controller I was able to do use something like this.
#query = "SELECT * FROM <table> WHERE <condition>;"
#result = <ClassName>.connection.execute(#query)
And after that I processed #result any way I wanted.

You can use Neo4j::Session.current.query to build general Cypher queries. Don't use START n=node anymore, that syntax isn't valid in future versions, so you should use MATCH (n) WHERE ID(n) = instead.
query = "MATCH (n)-[:has_comments]->(m) WHERE ID(n) = #{id} RETURN n, m"
result = Neo4j::Session.current.query(query).to_a
That'll give you an array of structs, with your results accessible by calling the n and m methods, respectively. I don't suggest you do it this way at all. As an alternative, you can do this:
result = Neo4j::Session.current.query.match("(n)-[:has_comments]->(m)").where("ID(n) = {id}").params(id: id).return(:n, :m)
You'll access the data the same way: n and m methods.
I don't recommend you do that, either. You're using Rails and ActiveNode, so you should have models and be able to do n_node.as(:n).comments(:m).pluck(:n, :m).

Related

How to avoid a product in Neo4J Cypher query?

I have the following Neo4J Cypher query:
MATCH (u:User{uid:'1819228'}),
(ctx:Context)-[:BY]->(u)
WITH DISTINCT ctx, u
MATCH (s:Statement)-[:IN]->(ctx),
(s)-[:BY]->(u)
RETURN DISTINCT s, ctx
ORDER BY s.timestamp ASC;
I have a feeling that something here is not efficient, because it runs pretty slow. Is it a case of creating a product with several query results?
What would be the best way to optimize this query to get the results in the same form?
This may be faster (and you may not need the DISTINCT):
MATCH (u:User)<-[:BY]-(s:Statement)-[:IN]->(ctx:Context)-[:BY]->(u)
WHERE u.uid = '1819228'
RETURN DISTINCT s, ctx
ORDER BY s.timestamp;
You may also want to create an index (or uniqueness constraint, which automatically creates an index) on :User(uuid), which will quickly find the desired User to start off the query.

Neo4j/Cypher - find nodes that link to all given nodes - the right way?

I would like to filter nodes that link to all given nodes.
I've tried this query which returns every page that has one of ['passionate', 'eye', 'ear'] :
MATCH (includeWord:Word) WHERE includeWord.Text IN ['passionate', 'eye', 'ear']
MATCH (p:Page)-[:CONTAINS]->(includeWord:Word)
// WHERE p LINKS TO ALL includeWord AT LEAST ONCE ?
RETURN DISTINCT p
This query didn't do the job either :
MATCH (p:Page)-[:CONTAINS]->(includeWord:Word)
WHERE includeWord.Text = 'passionate'
AND includeWord.Text = 'eye'
AND includeWord.Text = 'ear'
RETURN DISTINCT p
And programmatically speaking it's sort of ugly and unsecure, and I'm sure some of you out there know a better answer.
Maybe something like
MATCH (p:Page)-[:CONTAINS]->(includeWord:Word)
WHERE includeWord.Text IN_ALL ['passionate', 'eye', 'ear']
RETURN DISTINCT p
?
Thanks !
Oops,
I found this question neo4j cypher - how to find all nodes that have a relationship to list of nodes :
And for my query it works perfectly.
It looks like this :
MATCH (p:Page)-[:CONTAINS]->(word:Word)
WITH p, collect(word.Text) as words
WHERE ALL (v IN ['passionate', 'eye', 'ear'] WHERE v IN words)
RETURN p
It need a bit of reading before understanding !
I'm actually a bit surprised that that second query works. It's my understanding that a MATCH in cypher works by considering one subgraph at a time, so that would mean that it's impossible for any given :Word to have a Text that is both 'passionate' and 'eye' at the same time. I would expect that you would need to do something like:
MATCH
(p:Page),
p-[:CONTAINS]->(word1:Word),
p-[:CONTAINS]->(word2:Word),
p-[:CONTAINS]->(word3:Word)
WHERE
word1.Text = 'passionate',
word2.Text = 'eye',
word3.Text = 'ear'
RETURN p
Obviously that's a more complicated query, though...

Neo4j index not working without the Using keyword

If I execute this query
match (p:Person),(c:Customer) using index p:Person(BusinessEntityID) where p.BusinessEntityID = c.CustomerID return p
the response is very quick.
If I remove the using keyword and execute this.
match (p:Person),(c:Customer) where p.BusinessEntityID = c.CustomerID return p
, the query takes forever to return result. I have about 50,000 nodes.
Also, the .Net client does not implement Using Index and I am basically stuck.
Could you please help as to how I can speed up the query.
note: I have indexes created on both BusinessEntityID and CustomerID on labels :Person and :Customer respectively.
perhaps you should create a relationship between the two, not doing a manual join on a property?
Then, please change it to this:
match (c:Customer)
match (p:Person)
where p.BusinessEntityID = c.CustomerID
return p

Match several node property values in Cypher / Neo4J

using Cypher 2 I want to find all the nodes of a certain label (Context), which are called either "health" or "opinion".
The query that works is:
MATCH (c:Context) WHERE c.name="health" OR c.name="opinion" RETURN c;
But I'm wondering if Cypher has a syntax that I could put it into the first MATCH part, something like this:
MATCH (c:Context{name:"health"|name:"opinion})
The example above doesn't work, but I'm just showing it to let you know what I mean.
Thank you!
Alternatively, you can do this:
MATCH (c:Context) WHERE c.name IN ['health', 'opinion'] RETURN c
Still not in the "MATCH" statement, but a little easier as your list of possible values grows.
You could do
MATCH (c:Context {name:"health"}), (d:Context { name:"opinion"})
RETURN c,d

Running a case-insensitive cypher query

Is it possible to run a case-insensitive cypher query on neo4j?
Try that: http://console.neo4j.org/
When I type into this:
start n=node(*)
match n-[]->m
where (m.name="Neo")
return m
it returns one row. But when I type into this:
start n=node(*)
match n-[]->m
where (m.name="neo")
return m
it does not return anything; because the name is saved as "Neo". Is there a simple way to run case-insensitive queries?
Yes, by using case insensitive regular expressions:
WHERE m.name =~ '(?i)neo'
https://neo4j.com/docs/cypher-manual/current/clauses/where/#case-insensitive-regular-expressions
Another way would be:
WHERE LOWER(m.Name) = LOWER("Neo")
And if you are using the Neo4j Client (.NET):
Client.Cypher.Match("(m:Entity)")
.Where("LOWER(m.Name) = LOWER({name})")
.WithParam("name", inputName)
.Return(m => m.As<Entity>())
.Results
.FirstOrDefault();
If anybody is looking on how to do this with a parameter, I managed to do it like this.
query = "{}{}{}".format('Match (n) WHERE n.pageName =~ "'"(?i)", name, '" RETURN n')
and "name" is the variable or your parameter
You can pass a parameter to the case insensitive regular expression like:
WHERE m.name =~'(?i)({param})

Resources