This document discusses using hstore with Postgres and Rails to provide a NoSQL-like experience while integrating with a relational database. It explains how to enable hstore on a Postgres database, add an hstore field to a table, define accessors for known keys, perform queries on hstore values, and some limitations around data types and nesting. Hstore provides flexibility similar to NoSQL but avoids maintaining a separate database.
2. User
name :string
photo_url :string
verified? :bool
email :string
Twitter
LinkedIn
Yo
@yoniweisbrod
3. User
name :string
photo_url :string
verified? :bool
email :string
Twitter
profiles :hstore LinkedIn
Yo
@yoniweisbrod
4. > u = User.first
Not just a Hash
> u.profiles = {yo: “yoni_w”, linked_in: “yweisbrod”}
@yoniweisbrod
5. hstore
flexibility of NoSQL
integration with a relational database
no maintenance of an additional database
fully queryable
@yoniweisbrod
6. Enable hstore on your Postgres database
# db/migrate/20131220144913_enable_hstore.rb
def up
enable_extension “hstore"
end
def down
disable_extension “hstore”
end
@yoniweisbrod
7. Add the hstore field to your table
# db/migrate/20131220145432_add_profiles_to_users.rb
def change
add_column :users, :profiles, :hstore
end
@yoniweisbrod
8. Add accessor methods for known keys
class User < ActiveRecord::Base
store_accessor :profiles, :yo, :linkedin
end
User.first.yo
@yoniweisbrod
9. Great Rails Integration
• Add validations for specific keys
• Add indexes to speed up queries
@yoniweisbrod
10. Gotchas
• All strings
hstore_accessor gem
• No nested hashes.
nested-hstore gem
@yoniweisbrod
Hi, my name is Yoni Weisbrod. I’m a developer at a consultancy right here in sunny Tel Aviv called 500tech, and I’d like to take the next 5 minutes to share a really great feature that comes with Rails 4 that gives you the benefits of a NoSQL database, using your existing Postgres database. It’s access to Postgres’s hstore data type, and it allows you to store a hash in a database field.
Say you have a table of users with some standard fields, but there’s a group of data with attributes that you just can’t predict. For instance, we want to track users’ social network profiles, but it’s a group of programmers and everyone seems to be on different networks.
Some users have twitter, others have LinkedIn, and the most cutting edge insist on communicating with Yo.
(3) There’s obviously a relational database solution to this, but hstore gives us an elegant and convenient way to handle the unpredictability by storing the data as keys in a queryable hash.
On the surface, hstore looks like a regular serialised hash, but it’s actually far more powerful.
Hstore is an interesting choice because (1) it offers the flexibility of NoSQL, meaning you won’t need migrations to add future columns. (2) It’s fully integrated with the rest of your Postgres database, so you can still associate the record with other tables. (3) and you won’t need to maintain an additional database, such as MongoDB.
To use hstore on your database, there are 3 simple steps.
First, enable it on your Postgres database.
You can do this either with a migration, or by executing a command directly to your database. This is an example of a migration - just use ‘enable_extension “hstore”’.
(1) If you know that certain keys are likely to come up, you can add accessor methods for them
(2) so that you can access them with direct methods.
They really went all out with this feature, and you can do some great stuff with hstore. (1) You can add model validations on specific keys, now that you’ve set up accessor methods.
(2) Now hstore is incredibly powerful because you execute SQL queries on the data, which I’ll get to shortly. But to make it even more efficient, you can even store indexes like a normal column.
However, there are a couple gotchas.
First of all, everything (keys and values) are saved as strings, so no symbols or integers allowed.
Also, you can’t store a nested hash. If you try, the nested curly braces will just be escaped.
Fortunately, there’s a gem called “hstore_accessor”, which allows you to specify a data type for each attribute and translates the strings into the appropriate data types.
And there’s also nested-hstore, which allows you to store more complex hashes.
Of course, these aren’t native solutions so your mileage may vary.
I’ve left the best for last. Hstore’s power is in our ability to query data like a normal column, with some special syntax.
Using the arrow operand, you can query the value of a single key, as if you’re executing a standard SQL query.
All of the standard equality operands work here, such as “=“, “LIKE”, and “ILIKE” for case insensitive equality.
This tells us all user records with yo profiles named yoni.
But you can also query for the presence of a key with the question mark operand. This tells us all users with yo profiles.
You can also query for an array of keys. This is asking for all users who have yo profiles. You can also query all users who have Yo AND linked in using the ampersand, or all users who have either yo or linked in with the pipe.
Lastly, you can also query the presence of a key-value pair.