Upgrade Guide

Version 8.0 of the neo4j gem and version 7.0 of the neo4j-core gem introduce the most significant change to the Neo4j.rb project since version 3.0 when we introduced support for the HTTP protocol. With this update comes a number of breaking changes which will be outlined on this page

What has changed

The Neo4j.rb project was origionally created just to support accessing Neo4j’s embedded mode Java APIs via jRuby. In version 3.0 HTTP support was introduced, but the resulting code has been showing it’s age. An entirely new API has been created in the neo4j-core gem. The goal of this new API is only to support making Cypher queries to Neo4j either via HTTP, Bolt (Neo4j 3.0’s new binary protocol), or embedded mode in jRuby. The old code is still around to support connecting to Neo4j via it’s Java APIs, but we would like to later replace it with something simpler (perhaps in another gem).

The neo4j gem (which provides the ActiveNode and ActiveRel modules) has been refactored to use the new API in neo4j-core. Because of this if you are using ActiveNode/ActiveRel not much should change.

Before upgrading, the first thing that you should do is to upgrade to the latest 7.1.x version of the neo4j gem and the latest 6.1.x version of the neo4j-core gem. The upgrade from any previous gem > 3.0 should not be too difficult, but we are always happy to help on Gitter or Stackoverflow if you are having trouble

The neo4j-core gem

If you are using the neo4j-core gem without the neo4j gem, you should be able to continue using it as you have previously. It is recommended, however, that you refactor your code to use the new API. Some advantages of the new API:

  • The new binary protocol (“Bolt”) is supported
  • You can make multiple queries at a time
  • The interface is simpler
  • Node and relationship objects don’t change depending on the underlying query mechanism (Bolt/HTTP/embedded)
  • Path objects are now returned

One thing to note is that Node and Relationship objects in the new API are, by design, simple objects. In the old API you could get relationships and other information by calling methods on node or relationship objects. In the new API you must create Cypher queries for all data access.

The new API

To make a new session, you must first create an adaptor object and then provide it to the session new method:

neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::Bolt.new('bolt://user:pass@host:port', options)
# or
neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://user:pass@host:port', options)
# or
neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::Embedded.new('path/to/db', options)

neo4j_session = Neo4j::Core::CypherSession.new(neo4j_adaptor)

With your session object, you can make queries in a number of different ways:

# Basic query
neo4j_session.query('MATCH (n) RETURN n LIMIT 10')

# Query with parameters
neo4j_session.query('MATCH (n) RETURN n LIMIT {limit}', limit: 10)

Or via the Neo4j::Core::Query class

query_obj = Neo4j::Core::Query.new.match(:n).return(:n).limit(10)

neo4j_session.query(query_obj)

Making multiple queries with one request is support with the HTTP Adaptor:

results = neo4j_session.queries do
  append 'MATCH (n:Foo) RETURN n LIMIT 10'
  append 'MATCH (n:Bar) RETURN n LIMIT 5'
end

results[0] # results of first query
results[1] # results of second query

When doing batched queries, there is also a shortcut for getting a new Neo4j::Core::Query:

results = neo4j_session.queries do
  append query.match(:n).return(:n).limit(10)
end

results[0] # result

The neo4j gem

Sessions

In 7.0 of the neo4j-core gem, the new API doesn’t have the concept of a “current” session in the way that the old API did. If you are using neo4j-core, you must keep track of whatever sessions that you open yourself. In version 8.0 of the neo4j gem, however, there is a concept of a current session for your models. Previously you might have used:

Neo4j::Session.current

If you are using version 8.0 of the neo4j gem, that will be accessible, but neo4j is no longer using that old API to have a session with Neo4j. Instead you might use:

Neo4j::ActiveBase.current_session

server_db

In previous version of the neo4j gem to connect to Neo4j via HTTP you would define the value server_db in the neo4j.yml file, the NEO4J_TYPE environment variable, or a Rails configuration (config.neo4j.session.type). This should now be replaced and either bolt or http should be used depending on which connection type you need.

Also, instead of using session_type, session_url, session_path, and session_options, you should use session.type, session.url, session.path, and session.options respectively.

Some examples:

# config/neo4j.yml
# Before
development:
  type: server_db
  url: http://localhost:7474

# After
development:
  type: http # or bolt
  url: http://localhost:7474
# Rails config/application.rb, config/environments/development.rb, etc...

# Before
config.neo4j.session_type = :server_db
config.neo4j.session_url = 'http://localhost:7474'

# After
config.neo4j.session.type = :http # or :bolt
config.neo4j.session.url = 'http://localhost:7474'

Also, there was a slight change in the way that you configure the internal faraday adaptor of the neo4j-core gem:

# Before 8.0.x of `neo4j` gem
config.neo4j.session_options = {initialize: { ssl: { verify: true }}}

# After 8.0.x of `neo4j` gem
config.neo4j.session.options = {faraday_options: { ssl: { verify: true }}}

Outside of Rails

The neo4j gem will automatically set up a number of things with it’s railtie. If you aren’t using Rails you may need to set some things up yourself and some of the details have changed with version 8.0 of the neo4j gem.

Previously a connection with be established with Neo4j::Session.open and the default session from neo4j-core would be used. In version 7.0 of the neo4j-core gem, no such default session exists for the new API so you will need to establish a session to use the ActiveNode and ActiveRel modules like so:

adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://username:password@localhost:7474', wrap_level: :proc)

session = Neo4j::Core::CypherSession.new(adaptor)

Neo4j::ActiveBase.current_session = session

# Or skip setting up the session yourself:

Neo4j::ActiveBase.current_adaptor = adaptor

If you are using multiple threads, you should use the on_establish_session method to define how to setup your session. The current_session is stored on a per-thread basis and if you spawn a new thread, this block will be used to establish the session for that thread:

Neo4j::ActiveBase.on_establish_session do
  adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://username:password@localhost:7474', wrap_level: :proc)

  Neo4j::Core::CypherSession.new(adaptor)
end

Migrations:

If you would like to use the migrations provided by the neo4j outside of Rails you can include this in your Rakefile:

load 'neo4j/tasks/migration.rake'

Indexes and Constraints

In previous versions of the neo4j gem, ActiveNode models would allow you to define indexes and constraints as part of the model. While this was a convenient feature, it would often cause problems because Neo4j does not allow schema changes to happen in the same transaction as data changes. This would often happen when using ActiveNode because constraints and indexes would be automatically created when your model was first loaded, which may very well be in the middle of a transaction.

In version 8.0 of the neo4j gem, you must now create indexes and constraints separately. You can do this yourself, but version 8.0 provides fully featured migration functionality to make this easy (see the Migrations section).

If you still have indexes or constraints defined, the gem will check to see if those indexes or constraints exist. If they don’t, an exception will be raised with command that you can run to generate the appropriate migrations. If they do exist, a warning will be given to remove the index / constraint definitions.

Also note that all ActiveNode models must have an id_property defined (which is the uuid property by default). These constraints will also be checked and an exception will be raised if they do not exist.

Migrations

Version 8.0 of the neo4j gem now includes a fully featured migration system similar to the one provided by ActiveRecord. See the documentation for details.

neo_id id_properties

In version 8.0 of the neo4j gem support was added to allow for definining the internal Neo4j ID as the id_property for a model like so:

id_property :neo_id

Warning

Use of neo_id as a perminent identifier should be done with caution. Neo4j can recycle IDs from deleted nodes meaning that URLs or other external references using that ID will reference the wrong item. Neo4j may be updated in the future to support internal IDs which aren’t recycled, but for now use at your own risk

Exceptions

With the new API comes some new exceptions which are raised. With the new adaptor API errors are more dependable across different ways of connecting to Neo4j.

Old Exception New Exception
Neo4j::Server::Resource::ServerException Neo4j::Core::CypherSession::ConnectionFailedError
Neo4j::Server::CypherResponse::ConstraintViolationError Neo4j::Core::CypherSession::SchemaErrors::ConstraintValidationFailedError
Neo4j::Session::CypherError Neo4j::Core::CypherSession::CypherError
? ConstraintAlreadyExistsError
? IndexAlreadyExistsError