I have needed to store a lot of data in my time and Iíve used a lot of the big contenders: PostgreSQL, MySQL, SQLite, Redis, and MongoDB. While Iíve built up extensive experience with these tools, I wouldnít say that any of them have ever made the task fun. I fell in love with Ruby because it was fun and because it let me do more powerful things by not getting in my way. While I didnít realize it, the usual suspects of data persistence were getting in my way. But Iíve found a new love: let me tell you about Neo4j.
What is Neo4j?
Neo4j is a graph database! That means that it is optimized for managing and querying connections (relationships) between entities (nodes) as opposed to something like a relational database which uses tables.
Why is this great? Imagine a world with no foreign keys. Each entity in your database can have many relationships referring directly to other entities. If you want to explore the relationships there are no table or index scans, just a few connections to follow. This matches up well with the typical object model. It is more powerful, though, because Neo4j, while providing a lot of the database functionality that we expect, gives us tools to query for complex patterns in our data.
To connect to Neo4j weíll be using the neo4j gem. You can find instructions for connecting to Neo4j in your Rails application in the gemís documentation. Also the app with the code shown below is available as a running Rails app in this GitHub repository (use the sitepoint Git branch). When youíve got your database up and running use the rake load_sample_data command to populate your database.
Here is a basic example of an Asset model from an asset management Rails app:
has_many :out, :categories, type: :HAS_CATEGORY
Letís break this down:
The neo4j gem gives us the Neo4j::ActiveNode module, which we include to make a model.
The class name Asset means that this model will be responsible for all nodes in Neo4j labeled Asset (labels play a similar role to table names except that a node can have many labels).
We have a title property to describe the individual nodes
We have an outgoing has_many association for categories. This association helps us find Category objects by following HAS_CATEGORY relationships in the database.
With this model we can perform a basic query to find an asset and get itís categories:
2.2.0 :001 > asset = Asset.first
2.2.0 :002 > asset.categories.to_a
=> [#<Category uuid: "91cd5369-605c-4aff-aad1-b51d8aa9b5f3", name: "Classification">]
Anybody familiar with ActiveRecord or Mongoid will have seen this hundreds of times. To get a bit more interesting, letís define a Category model:
has_many :in, :assets, origin: :categories