Neo4jrbSpatial

Provides support for Neo4j Spatial to Neo4j.rb 5+.

It is more or less a Neo4j.rb-flavored implementation of Max De Marzi's code from Neography.

For support, open an issue or say hello through Gitter.

What it provides

  • Basic index and layer management
  • Basic node-to-index management
  • Hooks for Neo4j::ActiveNode::Query::QueryProxy models if you are using them

It is powered by an implementation of Neography's spatial module. Clearly, a huge debt is owed to Max De Marzi for doing all the hard work.

Requirements

  • Neo4j-core 5.0.1+
  • Neo4j Server 2.2.2+ (earlier versions will likely work but are not tested)
  • Ruby MRI 2.2.2+
  • Compatible version of Neo4j Spatial

Optionally:

Usage

Require it

# neo4j-core only?
require 'neo4j/spatial'

# neo4j gem/ActiveNode can omit the line above, just include the module in your model
include Neo4j::ActiveNode::Spatial

Basics - Neo4j-core

# Create an index
Neo4j::Session.current.create_spatial_index('restaurants')

# Create a node
node = Neo4j::Node.create({:name => "Indie Cafe", :lat => 41.990326, :lon => -87.672907 }, :Restaurant)

# Add a node to the index
Neo4j::Session.current.add_node_to_spatial_index('restaurants', node)

# Query around the index
Neo4j::Session.current.query.start('n = node:restaurants({location})').params(location: 'withinDistance:[41.99,-87.67,10.0]').pluck(:n)
# => CypherNode 90126 (70333884677220)

Basics - Neo4j gem

Neo4j.rb does not support legacy indexes, so a helper method is provided to add nodes. As with normal properties, your lat and lon should be explicitly declared.

Automatic index addition

At the moment, automatic index addition is not implemented.

Manual index addition

All of the Neo4j-core spatial methods accept ActiveNode-including nodes, so you can use them as arguments for all defined methods as you would Neo4j::Server::CypherNode instances.

Additionally, you can call the add_to_spatial_index instance method on any node to add it to its model's defined index.

Spatial queries

No helpers are provided to query against the REST API -- you'll need to use the ones provided for Neo4j-core; however, a class method is provided to make Cypher queries easier: spatial_match.

# Use the index defined on the model as demonstrated above
Restaurant.all.spatial_match(:r, params_string)
# Generates:
# => "START r = node:restaurants({params_string})"

It then drops you back into a QueryProxy in the context of the class. If you had an employees association defined in your model:

 # Find all restaurants within the specified distance, then find their employees who are age 30
 Restauarant.all.spatial_match(:r, 'withinDistance:[41.99,-87.67,10.0]').employees.where(age: 30)

Alternatively, if you did no define spatial_index on your model, you can feed a third argument: the index to use for the query.

Additional Resources

Check out the specs and the code for help, it's rather straightforward.

Max's blog post on using Neography with Spatial mostly works for an idea of the basics, just replace Neography-specific commands with their Neo4j-core versions.

Contributions

Pull requests and maintanence help would be swell. In addition to being fully tested, please ensure rubocop passes by running rubocop from the CLI.