Postgres JSON Functions From Rails


Say you are storing JSON in Postgres and need scopes to get records based on their JSON attributes. This post covers the use of JSON functions available in Postgres v9.3 to achieve this.

Suppose you have an Order class, containing a JSON blob that describes the product that the order relates to:

# == Schema Information
#
# Table name: orders
#
#  id                                    :integer  not null, primary key
#  customer_id                           :integer
#  product                               :json
#  created_at                            :datetime
#  updated_at                            :datetime

class Order < ActiveRecord::Base

end

Suppose product has the following structure:

{ "name": "Widget 01",
  "code": "W001",
  "plan": {
            "name": "Silver",
            "terms": "12 months"
          },
  "created_at": "2013-12-22 09:27:45 UTC",
  "updated_at": "2014-10-21 10:30:40 UTC"
}

And you want a scope on Order to find all orders with a particular code - something like Order.with_code("W001")

If you are using version 9.3 of Postgres, you can get it to do the heavy lifting for you using its JSON functions like so:

scope :with_code, ->(code) { where("product ->> 'code' = ?", code) }

Getting to nested JSON attributes is a bit trickier. Say you want a scope for all orders with a particular plan name - something like Order.with_plan_name("Silver")

scope :with_plan_name, ->(plan_name) { where("product::json #>> '{ plan,name }' = ?", plan_name) }

I got to these by looking through Stack Overflow posts, grokking the Postgres docs on JSON functions and this post of Avdi Grimm's. As usual, you can't comment here but if you see an error or want to offer a suggestion for improvement, please get in touch via email.