-
Notifications
You must be signed in to change notification settings - Fork 276
migrations
- By using migrations you can keep the code and the database in sync. There are two types of migrations : none lazy and lazy.
In a none lazy migration the database is upgraded/downgraded all at once, while in lazy migrations the node/relationship is only upgraded/downgraded when the node or relationship is loaded.
- A common usecase for migration is adding a lucene index on an existing database.
endprologue.
The nice thing about a schema free database like neo4j is that you
normally don’t need migrations.
You need migrations if you already have a system in production and
want to change the structure of that database without deleting it.
So, if you don’t have a system in production you simply delete the
database from your local machine and add modify your Neo4j classes
(e.g by adding timestamp properties or a new has_n relationship).
Here is an example of a use case for this feature.
Let say that we already have a database with nodes that have one property ‘name’.
Now we want to split that property into two properties: ‘surname’ and ‘given_name’.
We want to upgrade the database when it starts so we don’t use the lazy migration feature.
The neo4j database starts at version 0 by default.
Neo4j.migrate 1, "split name" do
up
# find all people and change
Person.all.each {|p|
self.surname = self[:name].split[0]
self.given_name = self[:name].split[1]
self[:name] = nil
end
Neo4j.ref_node.outgoing(:foo).each { do stuff }
end
down do
Person.all.each {|p|
self.name = "#{self[:surname]} {self[:given_name]}"
self[:surname] = nil
self[:given_name] = nil
end
Neo4j.ref_node.outgoing(:foo).each { do stuff }
end
end
If the code above has been loaded before the neo database starts it will automatically upgrade to version 1 (running all the migrations to the higest migration available).
You can force the neo4j to go to a specific version by using Neo4j#migrate!
method.
It’s also possible to have one version for each node class.
In the example above there is only one version for the whole database.
Example
class Person < Neo4j::Rails::Model
include Neo4j::Migrations::NodeMixin
rule(:all)
end
Person.migration 1, :split_name do
up do
all.each_raw do |node|
node[:given_name] = node[:name].split[0]
node[:surname] = node[:name].split[1]
node[:name] = nil
end
end
down do
all.each_raw do |node|
node[:name] = "#{node[:given_name]} #{node[:surname]}"
node[:surename] = nil
node[:given_name] = nil
end
end
In the example above we are using the all
method which are generated by using the rule rule(:all)
.
The up
and down
method are evaulated in the context of the class (Person).
The all.each_raw
method will return all node instances of type Person as Java nodes (node not wrapped in your Person class)
You can add lucene indexes with the Neo4j::Migrations::NodeMixin
.
Here is an example:
class Person
index :name
end
Person.migration 42, :add_some_index do
add_index :name
end
# add index on all previous nodes
Person.migrate!
When the migration is upgraded it will add the index :name.
Notice above that this index must be declared also in the Person class.
When downgrading the index will be removed.
You can also remove index just with the rm_index
method in the migration.
The example above can also be run as lazy migration. i.e. perform the upgrade/downgrade when the node is loaded instead of all at once.
The following example demonstrates this feature:
class Person < Neo4j::Rails::Model
include Neo4j::Migrations::LazyNodeMixin
end
Person.migration 1, :split_name do
# Split name into two properties
up do
self[:name]
self[:given_name] = self[:name].split[0]
self[:surname] = self[:name].split[1]
self[:name] = nil
end
down do
self.name = "#{self[:given_name]} #{self[:surname]}"
self.surename = nil
self.given_name = nil
end
end
Each node has a version property which is changed when an migration is executed.
The up
and down
blocks are evaluated in the context of the java node being loaded.
Migrations (Neo4j::Migrations::NodeMixin
) can also be used to add rules/functions on already existing nodes.
Let say we have the following class and that we already have existing nodes in the database of class Person.
class Person
include Neo4j::NodeMixin
end
Now we want to be able to find all instances of class Person. Since the Neo4j::NodeMixin
does not include
the rule rule :all
it is not possible by default to do that (unlike @Neo4j::Rails::Model which has this rule included).
The first step is adding the rule, open the class and add the rule :all and the MigrationMixin
.
class Person < Neo4j::Rails::Model
include Neo4j::Migrations::NodeMixin
rule :all
end
We now need to write an migration to upgrade all existing nodes.
Person.migration 1, "add rule :all" do
up do
Neo4j.all_nodes.each do |node|
Person.trigger_rules(node)
end
end
end
# Now update all existing nodes
Person.migrate!
Let say that we now have run the “add rule :all” migration from above.
We now want to add the count function so that Neo4j.rb increase a property when a new node is created.
This is for example needed when doing paging. Without this function neo4j will traverse all nodes in order to count them
which could be very slow.
First we open the Person class again and add the count function.
class Person
rule(:all, :functions => Neo4j::Functions::Count.new)
end
We now need to write a migration in order to upgrade all person nodes using this function.
Person.migration 2, "add count function" do
up do
func = Person.add_function_for(:all, Neo4j::Functions::Count)
Person.all.each do |node|
func.call(node)
end
end
end
This time there was no need to traverse every single node since we make use of the all
function that we added in the migration 1 above.
We can now make use the the Count function:
# return the number of Person nodes without traversing and counting them.
Person.all.count
If you set the configuration property migration_thread
to true all migration will be run in a new thread.
That means that you can still use the neo4j while the migration is taking place.
By default all migrations is run inside an transaction.
If you instead want to create your own transaction you can disable it with auto_transaction
Example:
Person.migration 2, :foo do
auto_transaction false
up do
Neo4j::Transaction.run {...}
end
..
end
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