Neo4j Rails
Contents |
Thanks to the workshop I started using Neo4j
Installing
update-java-alternatives --list
sudo apt install default-jre default-jre-headless
sudo apt-get install openjdk-8-jdk
wget -O - https://debian.neo4j.org/neotechnology.gpg.key | sudo apt-key add -
echo 'deb http://debian.neo4j.org/repo stable/' | sudo tee -a /etc/apt/sources.list.d/neo4j.list
sudo apt update
sudo apt install neo4j
lynx localhost:7474/browser
sudo neo4j start
# sudo mkdir /var/run/neo4j # this is needed if permission denied
# cat /etc/neo4j/neo4j.conf
# cat /var/log/neo4j/neo4j.log
# server will accepts connection on bolt://localhost:7687
# user:password neo4j:neo4j but it has to be changed
# reset password with: sudo rm /var/lib/neo4j/data/dbms/auth or
# sudo neo4j-admin set-initial-password ...
sudo service neo4j status
sudo service neo4j start
To enable remote access just uncomment the line
# /etc/neo4j/neo4j.conf
dbms.connectors.default_listen_address=0.0.0.0
For debugging you can also uncomment http logs so you can see if firewall is blocking
# /etc/neo4j/neo4j.conf
dbms.logs.http.enabled=true
Open browser on http://localhost:7474/ Since communications is over http/bold, you need to create new neo4j instance for each your project and environment. Use https://github.com/cohesivestack/ineo and install with the script
ineo instances
ineo status
ineo create -v 3.1.0 -p 7004 my_app_development
ineo create -p7006 my_app_test
ineo set-port my_app_development 7000 # this will change only http port
ineo destroy my_app_test
ineo delete-db my_app_test # this will clear only database
ineo versions
But I think bolt is not supported
Alternativelly you can use https://github.com/neo4jrb/neo4j-rake_tasks. Add
gem 'neo4j-rake_tasks'
. Note that there is no authentication enabled so do not
use on production.
# install neo4j to db/neo4j/development`
rake neo4j:install[community-latest,development]
rake neo4j:install[community-latest,test]
# To change the server port (default is 7474) type:
rails neo4j:config[development,$(expr $NEO4J_BOLT_PORT + 2)]
rails neo4j:config[test,$(expr $NEO4J_TEST_BOLT_PORT + 2)]
# vi db/neo4j/development/conf/neo4j.conf
# this will add something like this
# Bolt connector
dbms.connector.bolt.enabled=true
#dbms.connector.bolt.tls_level=OPTIONAL
dbms.connector.bolt.listen_address=localhost:7040
# HTTP Connector. There must be exactly one HTTP connector.
dbms.connector.http.enabled=true
dbms.connector.http.listen_address=localhost:7042
rake neo4j:start[development]
echo http://localhost:$(expr $NEO4J_BOLT_PORT + 2)
rake neo4j:start[test]
echo http://localhost:$(expr $NEO4J_TEST_BOLT_PORT + 2)
rails neo4j:stop[development]
kill -9 `cat db/neo4j/development/run/neo4j.pid`
Note that when you are changing the ports, then run spring stop
to reload new
env.
Usine neo4j with docker https://hub.docker.com/_/neo4j
docker pull neo4j
docker run --publish=7474:7474 --publish=7687:7687 --volume=$HOME/neo4j/data:/data neo4j
Learn from examples in browser, type :play movies
.
Cypher commands
:play_cypher
-
create node
()
and relationship[]
. In CREATE only directed relationships. Nodes can have 0 or more labels:Person
and can have different properties (strings, numbers or booleans). Relationships always have a direction and have a single type (:KNOWS
) and also properties.CREATE (d:Covek { name: 'Dusan' }), (m:Covek { name: 'Milan' }), (s:Covek { name: 'Srdjan' }), (d)-[:TWIN_BRO]->(m), (m)-[:TWIN_BRO]->(s), (m)-[:BRO]->(s), (d)-[:BRO]->(s)
- RETURN matched nodes and relationships, WHERE filter and what to RETURN, with
eventual: LIMIT 10.
MATCH (n:Covek) WHERE n.name = 'Dusan' RETURN n;
- match relationships by type
[edge:BRO]
. You can write long edgesMATCH (n)-[:BRO]->()<-[:BRO]-(m) RETURN n, m
- instead writting two edges
MATCH (n)-[]->(t), (t)-[]->(m)
you can write number of edges[*2]
or even interval of number[*1..4]
- if direction is ommited it will return twice (one in both directions)
MATCH (n)-[:BRO]-(m) RETURN n, m;
- WHERE can be moved inside node or edge declaration
MATCH (n:Covek { name: 'Dusan' }) RETURN n;
so WHERE is usualy used withWHERE NOT
. For example cocoautors which are not coauthors (not equal is<>
)
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors), (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors) WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors) AND tom <> cocoActors RETURN cocoActors.name AS Recommended, count(*) AS Strength ORDER BY Strength DESC
- RETURN can be node or edge,
Type()
,DISTINCT()
,
- match relationships by type
-
delete all nodes for
>2.3.0
MATCH (n) DETACH DELETE n
EXPLAIN
andPROFILE
will give more info about query
Neo4jrb
Follow https://neo4j.com/developer/ruby-course/ to create example app
asset_portal
, there is screen
cast episode 6 is advance
and links
https://gist.github.com/cheerfulstoic/3142ed2e15ad08ef6631
rails new asset_portal -m http://neo4jrb.io/neo4j/neo4j.rb -O
# this will add gem neo4j and neo4j-rake_tasks
# config/neo4j,yml
# db/neo4j folder
# config/application.rb uncomment server url with
config.neo4j.session.type = :bolt
config.neo4j.session.url = 'bolt://neo4j:dusan10@localhost:7687'
rails generate scaffold User name:string email:string
rails s
gnome-open http://localhost:3000/users
Model are defined with http://neo4jrb.readthedocs.io/en/9.0.x/ActiveNode.html
class User
include Neo4j::ActiveNode
has_many :out, :assets, type: :OWNS
end
class Asset
include Neo4j::ActiveNode
property :created_at, type: DateTime
property :updated_at, type: DateTime
has_one :in, :user, origin: :assets
end
- properties are declared with
property :name
. It can also definedefault: 'default_value'
is set when property isnil
so for new object it will be'default_value'
. For existing object you need to run migrationtype: Integer
define property type in ruby: integer, float, string, time, date, datetime, boolean, BigDecimal. Istead of DateTime, if you need some expensive query, better is to usetype: Integer
and store as unix timestamp- I have some problems with
serialize: :name
so I used plain olduser.name = { a: 3}.to_json
so I save hash or array to database. When I load, I need to deserialize to that objectJSON.parse user.name
enum status: [:draft, :published]
maps integer in db to strings in rails- you can use
user.draft!
,user.draft?
orUser.draft
_default: :draft
to define default value, note that default value is when value is NULL for existing objects, so better is to run migration (user.draft?
will return true even in neo4j it is NULL!!!) and you need to save two timesnext unless user.draft? ; user.status = :published; user.save! user.status = :draft; user.save!
- usually you need to add index on enum column but you can disable
_index: false
- validation like
validates :name, presence: true
, orvalidates_uniqueness_of :name
- you can pass undeclared properties if you insert the line
include Neo4j::UndeclaredProperties
- you can use
- relationship:
has_many :in, :posts
- first parameter can be
:in
,:out
,:both
. Once it is created, you should not change it (unless you write data migration) - second set the association name (can be overriden with
:model_class
and association name:type
) has_one
should be used with singular and.first
is automatically called so result is non chainable (unless you callcomment.post(chainable: true)
:type
override association name in Neo4j (Rails uses asociation name).type: false
match all relationships:model_class
is NODE model on other end of association, usualy resolved from second parametar - association name,model_class: false
will match any node on other end. Value can be a symbol with class name:model_class: :Asset
, or can be array in case of polymorphic associationhas_many :in, :written_post_or_comments, type: :WROTE, model_class: [:Post, :Comment]
. When using polymorphic than chains will not work unlessproxy_as
andquery_as
are used
http://neo4jrb.readthedocs.io/en/9.0.x/ActiveNode.html#polymorphic-associations
:rel_class
is REL model:origin
name of association in oposite model so you don’t need to write:type
in both classes, often used in:in
relationships. Value is the association name in reciprocal model,origin: :user
dependent: delete
to delete all associated nodes in cypher (:destroy
will call.each
and.destroy
with callbacks).:delete_orphans
delete associated records that have no other relationships of the same type (:destroy_orphans
do that in Ruby and callbacks will be called).unique: true
will useCREATE UNIQUE
relationship (only one).unique: :all
will create unless all nodes, type, direction and rel properties are matched.unique: { on: [keys] }
is looking only on keys to determine if already exists.- eager loading is implicit, but if you need explicit you can use
.with_associations(:tags, :comments)
to generateCOLLECT()
. For nested you can use hash and array notation: https://github.com/duleorlovic/premesti.se/blob/master/app/controllers/admin/users_controller.rb#L7@users = User.all.with_associations moves: { from_group: [:location], to_groups: [:location] }
CRUD associations
Comment.create post: post1, text: 'text' # create comment and relationship post.comments << comment3 # Creates new relationship post.comments.create comment3, posted_by: 'me' # text property on relationship # can not create like post1.comments.new text: '' since comment.post will not # be defined # remove association https://github.com/neo4jrb/neo4j/wiki/Neo4j%3A%3ARails-Persistence#destroy-and-delete post.comments = [comment1, comment2] # Removes all existing relationships comment.post = post1 # Removes all existing relationships post.comments.delete(comment) # destroys the relationship post.comments.find(comment).delete # destroys the relationship and node # update nodes post.comments.update_all flagged: true # update relationships post.comments.update_all_rels flagged: true # iterate over relationships post.comments.each_rel.map &:neo_id post.comments.each_with_rel { |node, rel| } # you can combine several associations post.comments.user.company # will return all companies for comments # find does not work if argument is AssociationProxy so you should use map # &:uuid # find_by or where has some problem if argument is array, so I use another # association and find [ids] to_location = move.to_groups.where(location: some_locations) to_location = move.to_groups.location.find(some_location.map(&:uuid)).first # custom query_as match pluck post.query_as(:p).match('(p)-[rel1:CONTAINS]->(n2)').where('rel1.on = true').pluck(:rel1) # with_associations and order @users = User.as(:u) .with_associations(moves: { from_group: [:location], to_groups: [:location] }) .order('u.last_sign_in_at DESC') # to find nodes that does not have relationship Move.query_as(:m).match('(m)').where('NOT (m)-[:WANTS]-()').pluck :m # to find nodes that does not have relation with EmailMessage with specific # property tag=some_tag User.query_as(:user).where("NOT (user)-[:RECEIVED]-(:EmailMessage { tag: '#{tag}'})").pluck(:user)
- first parameter can be
-
when comment is destroyed than you can not get it’s post, it is better to get it’s post before
def destroy post = @comment.post @comment.destroy redirect_to post_path post end
- callbacks like
before_save
Relationships is defined http://neo4jrb.readthedocs.io/en/9.0.x/ActiveRel.html
Type name will be the same as class name uppercased (:KNOWS
)
class Knows
include Neo4j::ActiveRel
from_class :user
to_class :any
property :created_at, type: DateTime
property :updated_at, type: DateTime
creates_unique
end
# create
Knows.create from_node: u, to_node: u
# fetch retreive
u.users.each_rel.to_a
u.users.each_with_rel.to_a
- it is not able to access relationships directly, always using a node
- properties are the same as for nodes
- usefull for polymophic, for example User knowns companies, places, … so it contains different logic for each relation.
Migration
You can generate migration to add new constrains. For new fields you can change models and start using it. To remove old fields you can also create migration.
rails g neo4j:migration AddUniqEmailToUsers
rake neo4j:generate_schema_migration[constraint,User,email]
Constrain is uniq and index. So to add uniq constrain you do not need to add index after that (only think is to remove if the index exists)
class ForceCreateUserEmailConstraint < Neo4j::Migrations::Base
def up
drop_index :User, :email, force: true
add_constraint :User, :email, force: true
end
end
Schema
http://neo4j.com/docs/developer-manual/current/cypher/schema/constraints/
Index and constraints are defined in migrations. To generate use
‘rake neo4j:generate_schema_migration[index|constraint
,Label
,property
]’
for example:
rake neo4j:generate_schema_migration[constraint,Person,uuid]
will generate
http://neo4j.com/docs/developer-manual/current/cypher/schema/constraints/
https://github.com/neo4jrb/neo4j/blob/5e0127f4bb3f3b523cf3f5a515f36e0468c287c5/docs/Migrations.rst#add_constraint
class ForceCreatePersonUuidConstraint < Neo4j::Migrations::Base
def up
add_constraint :Person, :uuid, force: true
end
def down
drop_constraint :Person, :uuid
end
end
code
This will add uniqueness constrain ASSERT person.uuid IS UNIQUE
, I think in
neo4j-core
implement that. I see in :schema
that we alse got a index.
Not sure how to generate existence ASSERT exists(person.uuid)
constraint.
http://neo4j.com/docs/developer-manual/current/cypher/schema/index/
Also you can add_index :Person, :email, force: true
.
Run migrations with
rake neo4j:migrate
Or use my shortcut rake db:migrate
, RAILS_ENV=test rake db:drop
and rake
db:seed
# lib/tasks/db.rake
namespace :db do
desc 'seed'
task seed: :environment do
b = {}
# User
[
{ var: :user1, email: '[email protected]' },
{ var: :user2, email: '[email protected]' },
{ var: :user3, email: '[email protected]' },
].each do |doc|
params = doc.except(:var).merge(name: doc[:var])
user = User.find_by params
unless user.present?
user = User.create! params.merge(password: 'asdfasdf', confirmed_at: Time.zone.now)
puts "User #{user.email}"
end
b[doc[:var]] = user if doc[:var]
end
# Location
[
{ var: :location1 },
{ var: :location2 },
{ var: :location3 },
{ var: :location4 },
{ var: :location5 },
].each do |doc|
params = doc.except(:var).merge(name: doc[:var])
location = Location.find_by params
if location.blank?
location = Location.create! params
puts "Location #{location.name}"
end
b[doc[:var]] = location if doc[:var]
end
# Group
[
{ var: :g2_l1, location: b[:location1], age_min: 2,
age_max: 2 },
{ var: :g2_l2, location: b[:location2], age_min: 2,
age_max: 2 },
{ var: :g2_l3, location: b[:location3], age_min: 2,
age_max: 2 },
{ var: :g2_l4, location: b[:location4], age_min: 2,
age_max: 2 },
{ var: :g2_l5, location: b[:location5], age_min: 2,
age_max: 2 },
{ var: :g4_l1, location: b[:location1], age_min: 4,
age_max: 4 },
].each do |doc|
params = doc.except(:var).merge(name: doc[:var])
group = Group.find_by params
unless group.present?
group = Group.create! params
puts "Group #{group.name}"
end
b[doc[:var]] = group if doc[:var]
end
# Move
[
{ var: :m1_l1_l2, from_group: b[:g2_l1], prefered_groups: b[:g2_l2],
user: b[:user1] },
{ var: :m1_l1_l3, from_group: b[:g2_l1], prefered_groups: b[:g2_l3],
user: b[:user1] },
{ var: :m2_l3_l4, from_group: b[:g2_l3], prefered_groups: b[:g2_l4],
user: b[:user2], available_from_date:
Date.today.end_of_month },
{ var: :m3_l4_l1, from_group: b[:g2_l4], prefered_groups: b[:g2_l1],
user: b[:user3], }
].each do |doc|
params = doc.except(:var).merge(name: doc[:var])
move = Move.find_by params
unless move.present?
move = Move.create! params
puts "Move #{move.name}"
end
end
end
desc 'drop'
task drop: :environment do
Rake::Task["neo4j:stop"].invoke Rails.env
puts sh "rm -rf db/neo4j/#{Rails.env}/data/databases/graph.db"
Rake::Task["neo4j:start"].invoke Rails.env
puts "Find database on http://" +
Rails.application.secrets.neo4j_host.to_s + ":" +
(Rails.application.secrets.neo4j_bolt_port.to_i + 2).to_s
end
desc 'migrate'
task migrate: :environment do
puts "running neo4j:migrate"
Rake::Task["neo4j:migrate"].invoke Rails.env
end
desc 'setup = drop, migrate and seed'
task setup: :environment do
puts 'this is not implemented'
puts 'since drop need some time to bootup, and migrate raises exception'
end
end
In migration def change
should be replaced with def up
and def down
since
there is an error:
rake aborted!
NotImplementedError: NotImplementedError
If using the bold, in migrations there are exception https://github.com/neo4jrb/neo4j-core/issues/303
rake aborted!
should be implemented!
Test data should be wiped manually http://neo4jrb.readthedocs.io/en/8.0.x/Miscellany.html#cleaning-your-database-for-testing There are attempts to use database_cleaner gem https://github.com/neo4jrb/neo4j/issues/1368 https://github.com/DatabaseCleaner/database_cleaner/issues?utf8=%E2%9C%93&q=Neo4j https://github.com/DatabaseCleaner/database_cleaner/pull/481/files
# test/test_helper.rb
class ActiveSupport::TestCase
# http://neo4jrb.readthedocs.io/en/8.0.x/Miscellany.html#cleaning-your-database-for-testing
teardown do
Neo4j::ActiveBase.current_session.query %(
MATCH (n)
WHERE NOT (n:`Neo4j::Migrations::SchemaMigration`)
DETACH
DELETE n
)
end
end
In tests you can not use fixtures. Maybe raw cypher can help https://github.com/neo4jrb/neo4j/issues/611
query = %(
CREATE (c:City),
(l_a:Location),
(l_b:Location),
(l_a)-[:IN_CITY]->(c),
(l_b)-[:IN_CITY]->(c),
)
Neo4j::ActiveBase.current_session.query query
but best advice to use factory girl.
Query
Debug with user.assets.categories.assets.print_cypher
or some query move.query_as(:m1).match('(m1)-[]-(g:Group)').to_cypher
(similar to_sql
)
Query on property User.where(name: ?)
parametar ?
can be: string, nil,
array, regular expression User.where(name: /.*dule.*/i)
, range
User.where(age: 1..2)
.
If you use params inside where string you should use params to excape and prevent injection attack https://github.com/neo4j/neo4j/issues/1983 https://neo4jrb.readthedocs.io/en/5.2.x/Querying.html#parameters
Location.query_as(:location).where("location.name_en =~ {name_en}").params(name_en: "(?iu).*#{@term}.*").pluck(:location)
There is neo_id
on each node and relationships but are somewhat volatile so do
not use it. Instead, each new node requires primary key uuid
property which is
also accessed using .id
method. Rels do not have ids since they are traversed
by nodes. SecureRandom uuid is generated in migration rake
neo4j:generate_schema_migration[constraint,Model,uuid]
and rake neo4j:migrate
Raw query can be done using Neo4j::ActiveBase.current_session.query('MATCH (n)
RETURN n LIMIT {limit}', limit: 10)
or when searching for maximum
But it is better to use ActiveNode
finders:
# find by id_property
User.find my_uuid
# find by any property property
User.find_by name: 'Dule'
# find by associations
User.find_by from_group: Group.last
# find_by supports only single value even it is has_many
User.find_by to_groups: Group.last
# you can use where with associations
User.all.where to_groups: Group.last
Queries can be chained in 3 ways: Model.all
, Model.association
,
model_object.association
. It returns AssociationProxy
.
If where
is used, than QueryProxy
is returned.
Query object is used to simplify on which fields is used:
User.query_as(:user).where(user: { age: 1..2 }).pluck(:user)
You can use where
or rel_where
in the middle of a chain (it is applied to
last) for example user.created_assets.where(public: true).categories
.
Also .order
, .limit
and .skip
.
You can pass single attribute to assign variable in cypher, so we can pluck on
it user.created_assets.categories(:category).pluck('category.name',
'count(*)')
Using where
can be with string or with hash. If you want to target specific
node you can use string like where("node.uuid = '#{n.id}'")
or hash
where(node: { neo_id: n.id })
, or using parms where('node.uuid =
{node_id}').params(node_id: n.id)
or match_nodes(node: n)
.
Note that you have to use uuid
since id
in cypher does not exists. For a
list you do not need to wrap in square brackets where('node.uuid IN
{node_ids}').params(node_ids: @nodes.map(&:uuid))
.
https://github.com/neo4jrb/neo4j-core/blob/8.0.x/spec/neo4j-core/unit/query_spec.rb#L373
https://github.com/neo4jrb/neo4j-core/blob/8.0.x/spec/neo4j-core/unit/query_spec.rb#L474
Regular expression
You can search with case insensitive regex https://neo4j.com/docs/developer-manual/current/cypher/clauses/where/#case-insensitive-regular-expressions
Devise
gem 'devise-neo4j'
bundle
rails g devise:install --orm=neo4j
rails g neo4j:devise User
Heroku
export MYAPP_NAME=my-app # only dash, not underscore
heroku apps:create $MYAPP_NAME
heroku addons:create graphenedb
heroku buildpacks:set https://github.com/heroku/heroku-buildpack-ruby
heroku buildpacks:add --index 1 https://github.com/heroku/heroku-buildpack-nodejs
heroku buildpacks # should return 1. nodejs 2. ruby (latest wins :)
heroku config # copy all GRAPHENEDB_BOLT... variables
# use http, not bolt port
heroku config:set NEO4J_TYPE=https NEO4J_HOST= NEO4J_PORT= NEO4J_USERNAME= NEO4J_PASSWORD=
heroku run rake db:migrate
heroku run rake db:seed
You can export from Graphenedb graphdb.zip
https://docs.graphenedb.com/docs/importing-and-exporting-databases. To restore
localy you need to copy files to neo4j/data/graph.db/
Tips
Model your entity attribute as property on a node if
- it is simple value and there is no need to qualify relationship.
Otherwise:
- use relationship to a new node instead of property of a node in cases where
you need to add another relationships to it. For example instead of property
user_id
on relationship you should useUser
node with:OWNS
relationship to it, since you will probably add another relation to thatUser
- use relationship if there is a need to specify something relationship (for example profiency in a skill)
- use relationship if its a complex property like multiple fields (address) So rule is to use node if you need start a query from this entity like skill ruby -> users.
Instead to name relationship with :BELONGS_TO
use something more meaningfull
to businness so you know what it is about:
- something belongs to Category use
something-[:IN_CATEGORY]->category
- for review
[:REVIEW_FOR]
. - For has_many use verb
()-[:POSTS]->(:Post)
, or[:CONTAINS]
,[:USING]
,[:MENTIONS]
- For has_and_belongs_to_many use whatever
(:User)-[:FRIENDS]->(:User)
,(Tweet)-[:RETWEETS]->(:Tweet)
Common Graph stuctures:
- Intermediate Nodes: when when you have three or more entity in single context: ‘Ian bought a book in Mercator’, ‘Patrick work at Trk in role Designer’ …
- Linked List: entities are linked as sequence, you need to traverse: ‘Job history’, ‘Broadcast or Production of Movies’
- Versioning Graphs: time based
- structure: we have idendtity nodes as placeholders and timestamped relationships.
- state: every note is snapshot,
-
ignore case is with
(?i)
but for cyrilic we need(?iu)
, for exampleMATCH (d:Covek) WHERE d.nameL =~ '(?iu).*DUŠAN.*' RETURN d
https://github.com/neo4j/neo4j/issues/1983 - use
gem 'rack-mini-profiler'
to see actual numbers of queries - use kaminari for pagination… use proxy_as instead of changing the scope to
associations
Errors
Error defined for a second time. Associations can only be defined once
is when
you name the associataion with already used name. Please use different name and
same model_class.
In migration rails aborted! Neo4j::MigrationError: Duplicate constraint for
Location
means that there exists in schema so you need to manually remove.
You can use :schema
or CALL db.constraints
to see all constrains and you can
drop with
DROP CONSTRAINT ON (l:Location) ASSERT l.uuid IS UNIQUE
To wipe all data, destroy clear database, remove graph.db and restart.
rake neo4j:stop[development]
rm -rf db/neo4j/development/data/databases/graph.db
rake neo4j:start[development]
ArgumentError: Invalid value for 'city' condition
is error in seed task when
you assign symbol :city1
instead of object b[:city1]
If you open rails c
console1 and than rails c
console2, and exit
in
console1, it will not exit. You need to exit
console2 to release something and
both consoles exists… When rails console hangs than spring stop
helps.
I got some error:
Neo4j::Core::CypherSession::CypherError ( Cypher error:
Neo.DatabaseError.Transaction.TransactionStartFailed: Database has encountered some problem, please perform necessary action (tx recovery/restart)
):
For which I restart my machine to recover from this error.
Error
Neo4j::DeprecatedSchemaDefinitionError: Some schema elements were defined by the model (which is no longer supported), but they do not exist in the database. Run the following to create them if you haven't already:
rake neo4j:generate_schema_migration[constraint,Chat,uuid]
And then run `rake neo4j:migrate`
(zshell users may need to escape the brackets)
can be solved with
RAILS_ENV=test rake neo4j:migrate
heroku run rake neo4j:migrate:status
# try adding force: true so there is no error when performing migrations
class CreateChat < Neo4j::Migrations::Base
def up
add_constraint :Chat, :uuid, force: true
end
def down
drop_constraint :Chat, :uuid
end
end
Error
Neo4j::Core::CypherSession::CypherError: Cypher error:
Neo.DatabaseError.Transaction.TransactionStartFailed: The database has encountered a critical error, and needs to be restarted. Please see database logs for more details.
There is a problem when there exists a node when searching by relation but does
not exists when searching by n.uuid
Todo
rails g model
will generate model files with rubocop offencies
rails neo4j:migrate
event it is successfull, generate error message:
should be implemented!
https://github.com/neo4jrb/neo4j-core/issues/303
device-neo4j generate two migrations with same id… Best solution is to rename migration and clear database.
Errors format should be used:
Dump
On Heroku GrapheneDB in tab Admin -> Export database, you can download
graphdb.zip
and export to your graph.db folder
export GRAPH_DB_PATH=db/neo4j/development/data/databases/graph.db
rm -rf $GRAPH_DB_PATH
mkdir $GRAPH_DB_PATH
unzip tmp/graphdb.zip -d $GRAPH_DB_PATH
rails neo4j:restart[development]
To dump to production you need also to restart heroku
wget 'graphdb_url'
mv graphdb.zip
export GRAPH_DB_PATH=/var/lib/neo4j/data/databases/graph.db
sudo rm -rf $GRAPH_DB_PATH
sudo -u neo4j mkdir $GRAPH_DB_PATH
sudo -u neo4j unzip graphdb.zip -d $GRAPH_DB_PATH
sudo service neo4j restart
heroku restart
tail -f /var/log/neo4j/debug.log
To make a backup you can
# we have to cd to directory because otherwise zip will store path in output
cd db/neo4j/development/data/databases/graph.db/
zip -r ../backup.zip .
Links
- http://neo4jrb.io/ and differences with sql http://neo4j.com/product/
- http://neo4jrb.readthedocs.io/en/7.0.x/
- youtube series https://www.youtube.com/watch?v=n0P0pOP34Mw
- https://devchat.tv/ruby-rogues/236-rr-neo4j-with-brian-underwood
Todo https://youtu.be/78r0MgH0u0w 42min time versioned graphs https://youtu.be/AaJS-DGBQX4