-
Notifications
You must be signed in to change notification settings - Fork 275
Search and Match
There are a few ways to find and return nodes.
find
returns one ruby object or nil if none was found.
# Example, find by id (neo_id or defined by id_property)
Blog.find(4242)
find_by
and find_by!
behave as they do in ActiveRecord, returning the first object matching the criteria or either nil or an error in the case of find_by!
Blog.find_by(title: 'Neo4j.rb is awesome')
The Cypher DSL is referred to within Neo4j.rb as QueryProxy. It is thought of as a "proxy" because it acts as an interface for the Query class in Neo4j::Core. All QueryProxy methods are chainable and lazily executed.
All of the following result in enumerable results:
# Find all blog models
Blog.all
# Where results
Blog.all.where(title: 'neo4j')
# Order
Person.all.where(age: 30).order(age: :desc).limit(5)
The methods used to access associations in models are valid QueryProxy methods and can be chained together to create complex queries.
Assuming the following:
class Student
include Neo4j::ActiveNode
has_many :out, :lessons, type: 'enrolled_in'
end
class Lesson
include Neo4j::ActiveNode
has_many :in, :students, origin: :lesson
has_many :out, :teachers, type: 'taught_by'
end
class Teacher
include Neo4j::ActiveNode
property :age
has_many :in, :lessons, origin: :teachers
end
class EnrolledIn
include Neo4j::ActiveRel
from_class: Student
to_class: Lesson
type: 'enrolled_in'
property: :start_date, type: Date
property: :end_date, type: Date
end
s = Student.first
# find all the student's lessons
s.lessons
# find all of the teachers of their lessons
s.lessons.teachers
# find all of the teachers of their lessons who are age 34
s.lessons.teachers.where(age: 34)
# find all of the teachers, age greater than 34, who teach lessons of level 102, but return the lessons
s.lessons(:l).where(level: 102).teachers(:t).where('t.age > 34').pluck(:l)
# find all of the lessons the student was enrolled in on 2014-11-22
s.lessons(:l, :r).where("r.start_date < {the_date} and r.end_date >= {the_date}").params(the_date: '2014-11-22').pluck(:l)
When using quotes within a where
clause, you can use full cypher syntax. See http://docs.neo4j.org/chunked/stable/query-syntax.html.
Another option is rel_where
, which will target the most recent relationship identifier in a QueryProxy chain.
s.lessons(:l, :r).where(subject: 'Math').rel_where(grade: 85)
All queries are parameterized when using hashes. If you need to use a string in where
, you should set the parameter manually.
Student.all.where(age: params[:age], name: params[:name], home_town: params[:home_town]).first
Student.all.where("s.age < {age} AND s.name = {name} AND s.home_town = {home_town}").params(age: params[:age], name: params[:name], home_town: params[:home_town]).pluck(:s)
You can move a QueryProxy chain to Neo4j::Core::Query with query_as
method. From here, you have a Query object which and can use the more explicit Query DSL. See the documentation in the (neo4j-core gem)[https://github.com/neo4jrb/neo4j-core].
# Find all comments for any blog which have the world "pottery"
result = Blog.query_as(:blog).match("blog<-[:COMMENTS_ON]-(comment:Comment)").where(comment: {body: /pottery/}).pluck(:blog, :comment)
result.first.blog # First blog
result.first.comment # Comment
# Find all comment authors whose age is greater than 30
blog.query_as(:blog).match("blog<-[:COMMENTS_ON]-(:Comment)<-[:AUTHORED]-(author:Person)").where("author.age > 30").pluck(:author)
# You can even get start with basic query methods and then transfer to detailed querying
blog.where(title: 'neo4j').query_as(:blog).match("blog<--(comment:Comment)").where("comment.created_at >= '2014-07-09'").pluck(:comment)
For more information on Query objects, see the (Neo4j::Core::Query documentation)[https://github.com/neo4jrb/neo4j-core/wiki/Queries#examples].
An explicit return method does not need to be called if you want to return the last matching node in a query chain.
User.where(age: 30).lessons.where(level: 101)
Calling each
on this would iterate through objects of class Lesson, no need to tell it what to return.
If you want something other than the last object or you want distinct results, use pluck
or return
. return
is a method from neo4j-core and is usable after calling query
or query_as
, so see neo4j-core docs for examples. This will focus on pluck
.
pluck
is used to return matched nodes or relationships in queries. There are two reasons to use it:
You want to return a node or group of nodes from a query other than just the nodes at the end of the chain.
#pluck not needed, returns the lessons that are level 101 of all users who are age 30
User.where(age: 30).lessons.where(level: 101)
#call each, first, include?, etc,...
#return the users who are age 30 and have lessons with level 101
User.as(:u).where(age: 30).lessons.where(level: 101).pluck(:u)
#return both the users and the lessons
User.as(:u).where(age: 30).lessons(:l).where(level: 101).pluck(:u, :l)
You want distinct results.
#assign your node an identifier, call pluck with a string
User.where(age: 30).lessons(:l).where(level: 101).pluck('DISTINCT l')
In both cases, pluck expects a node identifier.
You can also pluck relationships based on their identifiers.
# return the relationship between users, age 30, who have lessons with level 101
User.where(age: 30).lessons(:l, :rel).where(level: 101).pluck(:rel)
Note that plucking the relationship may not be necessary if you plan on iterating through the results with each
.
User.where(age: 30).lessons(:l, :rel).where(level: 101).pluck(:rel).each do |rel|
# is equivalent to...
User.where(age: 30).lessons.where(level: 101).each_rel do |rel|
# or with both nodes and relationships
User.where(age: 30).lessons.where(level: 101).each_with_rel do |lesson, rel|
There are two methods, match_to
and first_rel_to
that both make simple patterns easier.
In the most recent release, match_to
accepts nodes; in the master branch and in future releases, it will accept a node or an ID. It is essentially shorthand for association.where(neo_id: node.neo_id)
and returns a QueryProxy object.
# starting from a student, match them to a lesson based off of submitted params, then return students in their classes
student.lessons.match_to(params[:id]).students
first_rel_to
will return the first relationship found between two nodes in a QueryProxy chain.
student.lessons.first_rel_to(lesson)
# or in the master branch, future releases
student.lessons.first_rel_to(lesson.id)
This returns a relationship object.
Finding in batches will soon be supported in the neo4j gem, but for now is provided in the neo4j-core gem (documentation)
You can also use the orm_adapter API, by calling #to_adapter on your class. See the API, https://github.com/ianwhite/orm_adapter
Same as in neo4j-core, see Neo4j::Session.query
WARNING: Much of the information in this wiki is out of date. We are in the process of moving things to readthedocs
- Project Introduction
- Neo4j::ActiveNode
- Neo4j::ActiveRel
- Search and Scope
- Validation, Uniqueness, and Case Sensitivity
- Indexing VS Legacy Indexing
- Optimized Methods
- Inheritance
- Core: Nodes & Rels
- Introduction
- Persistence
- Find : Lucene
- Relationships
- Third Party Gems & extensions
- Scaffolding & Generators
- HA Cluster