-
Notifications
You must be signed in to change notification settings - Fork 276
Neo4j::wrapper introduction
You can use the neo4j-wrapper gem when you don't need rails but still need a mapping to Ruby classes for Neo4j nodes and relationships. The neo4j-wrapper is included in the neo4j gem but can also be used standalone, check the github project.
The neo4j-wrapper gem defines these mixins:
The following example shows how to map a Neo4j node to a Ruby Person instance.
require "rubygems"
require "neo4j-wrapper"
class Person
include Neo4j::NodeMixin
# define Neo4j properties, with exact lucene index
property :name, :index => :exact
property :salary, :index => :exact
property :age, :index => :exact
property :country, :index => :exact
# define an one way relationship to any other node
has_n :friends
end
Neo4j properties and relationships are declared using the 'property' and 'has_n'/'has_one' NodeMixin class method. Adding new types of properties and relationships can also be done without declaring those properties/relationships by using the operator '[]' on @Neo4j::NodeMixin@ and the '<<' on the @Neo4j::NodeTraverser@
By using the NodeMixin and by declaring properties and indices, all instances of the Person class can now be stored in the Neo4j node space and be retrieved/queried by traversing the node space or performing Lucene queries.
A Lucene index will be updated when the name or salary property changes.
Creating a Person node instance
person = Person.new
Setting a property:
person.name = 'kalle'
person.salary = 10000
You can also set this (or any property) when you create the node:
person = Person.new :name => 'kalle', :salary => 10000, :foo => 'bar'
Notice that it is not required to specify which attributes should be available on a node. Any attributes can be set using the [] operator. Declared properties set an expectation, not an requirement. It can be used for documenting your model objects and catching typos.
Example:
person['an_undefined_property'] = 'hello'
So, why declare properties in the class at all? By declaring a property in the class, you get the sexy dot notation. Also, when using Neo4j.rb from Ruby on Rails you sometimes need to declare properties on your models to get accepts_nested_attributes_for and ActiveModel::MassAssignmentSecurity working.
You can get all properties as an hash.
Example:
puts "person #{person.props.inspect}"
You can also update any properties with an hash
Example:
person.update( :name => 'foo', :age => 42, :colour => nil)
Like properties, relationships do not have to be defined using has_n or has_one for a class. A relationship can be added at any time on any node.
Example:
person.outgoing(:best_friends) << other_node
person.rels(:outgoing, :best_friends).first.end_node # => other_node (if there is only one relationship of type 'best_friends' on person)
Use to and from with has_n to specify which direction the generated method should traverse.
Example
class Role
include Neo4j::RelationshipMixin
# notice that neo4j relationships can also have properties
property :name
end
class Actor
include Neo4j::NodeMixin
# The following line defines the acted_in relationship
# using the following classes:
# Actor[Node] --(Role[Relationship])-- Movie[Node]
#
has_n(:acted_in).to(Movie).relationship(Role)
end
class Director
include Neo4j::NodeMixin
property :name
has_n(:directed).to(Movie)
end
class Movie
include Neo4j::NodeMixin
property :title
property :year
has_one(:director).from(Director, :directed)
# defines a method for traversing incoming acted_in relationships from Actor
has_n(:actors).from(Actor, :acted_in)
end
You can then do this:
lucas = Director.new :name => 'George Lucas'
star_wars_4 = Movie.new :title => 'Star Wars Episode IV: A New Hope', :year => 1977
star_wars_3 = Movie.new :title => "Star Wars Episode III: Revenge of the Sith", :year => 2005
lucas.directed << star_wars_3 << star_wars_4
lucas.directed.should include(star_wars_3, star_wars_4)
star_wars_3.director.should == lucas
star_wars_4.director.should == lucas
Which is same as:
lucas.outgoing("Movie#directed").should include(star_wars_3, star_wars_4)
star_wars_3.incoming("Movie#directed").should include(lucas)
There are three ways of finding/querying nodes in Neo4j:
- by traversing the graph
- by using Lucene queries
- using the unique neo4j id (Neo4j::NodeMixin#neo_id).
- Using Cypher
When doing a traversal one starts from a node and traverses one or more relationships (one or more levels deep). This start node can be either the reference node which is always found (Neo4j#ref_node) or by finding a start node from a Lucene query.
- Using the @Enumerable#sort_by@
- Using lucene, see "Indexing and Quering with Lucene":lucene.html
- Using @Neo4j::NodeMixin#has_list@, see above
- Implement your own "indexing" tree in neo4j
It works as expected, example:
class Vehicle
include Neo4::NodeMixin
property :wheels
index :wheels
end
class Car < Vehicle
end
Car.all # => returns all cars
Vehicle.all # => returns all vehicles
class Company
include Neo4j::NodeMixin
has_n(:employees)
end
class Person
include Neo4j::NodeMixin
property :name
property :age, :size, :type => Fixnum, :index => :exact
property :description, :index => :fulltext
has_one(:best_friend)
has_n(:employed_by).from(:employees)
end
Neo4j::Transaction.run do
Person.new(:name => 'jimmy', :age => 35)
end
person = Person.find(:age => (10..42)).first
Neo4j::Transaction.run do
person.best_friend = Person.new
person.employed_by << Company.new(:name => "Foo ab")
end
# find by navigate incoming relationship
company = person.employed_by.find { |p| p[:name] == 'Foo ab' }
puts "Person #{person.name} employed by #{company[:name]}"
# navigate the outgoing relationship:
company.employees.each {|x| puts x.name}
There is a complete example here
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