Adds typed jsonb backed fields as first class citizens to your ActiveRecord models. This gem is similar in spirit to HstoreAccessor, but the jsonb column in PostgreSQL has a few distinct advantages, mostly around nested documents and support for collections.
It also adds generic scopes for querying jsonb columns.
The default option works pretty much as you would expect in practice; if no values are set for the attributes, a hash of the specified default values is saved to the jsonb column.
Jsonb Accessor provides several scopes to make it easier to query jsonb columns. jsonb_contains, jsonb_number_where, jsonb_time_where, and jsonb_where are available on all ActiveRecord::Base subclasses and don't require that you make use of the jsonb_accessor declaration.
If a class does have a jsonb_accessor declaration, then we define one custom scope. So, let's say we have a class that looks like this:
If you want to search for records within a certain time, date, or number range, just pass in the range (Note: this is just shorthand for the above mentioned before/after/less_than/less_than_or_equal_to/greater_than_or_equal_to/etc options).
This scope is a convenient wrapper around the jsonb_wherescope that saves you from having to convert the given keys to the store keys and from specifying the column.
jsonb_where
Works just like the scope above except that it does not convert the given keys to store keys and you must specify the column name. For example:
This scope makes use of the jsonb_contains, jsonb_number_where, and jsonb_time_wherescopes.
jsonb_where_not
Just the opposite of jsonb_where. Note that this will automatically exclude all records that contain null in their jsonb column (the data column, in the example below).
Returns all records that contain the given JSON paths.
Product.all.jsonb_contains(:data,title: "foo")Product.all.jsonb_contains(:data,reviewed_at: 10.minutes.ago,p: 12)# Using the store key
Note: Under the hood, jsonb_contains uses the @> operator in Postgres so when you include an array query, the stored array and the array used for the query do not need to match exactly. For example, when queried with [1, 2], records that have arrays of [2, 1, 3] will be returned.
jsonb_excludes
Returns all records that exclude the given JSON paths. Pretty much the opposite of jsonb_contains. Note that this will automatically exclude all records that contain null in their jsonb column (the data column, in the example below).
Product.all.jsonb_excludes(:data,title: "foo")Product.all.jsonb_excludes(:data,reviewed_at: 10.minutes.ago,p: 12)# Using the store key
jsonb_number_where
Returns all records that match the given criteria.
Returns all records that do not match the given criteria. It's the opposite of jsonb_number_where. Note that this will automatically exclude all records that contain null in their jsonb column (the data column, in the example below).
It supports before and after and is indifferent to strings/symbols.
jsonb_time_where_not
Returns all records that match the given criteria. The opposite of jsonb_time_where. Note that this will automatically exclude all records that contain null in their jsonb column (the data column, in the example below).
One of the big issues with ActiveRecord single-table inheritance (STI)
is sparse columns. Essentially, as sub-types of the original table
diverge further from their parent more columns are left empty in a given
table. Postgres' jsonb type provides part of the solution in that
the values in an jsonb column does not impose a structure - different
rows can have different values.
From here any attributes specific to any sub-class can be stored in the
jsonb column avoiding sparse data. Indices can also be created on
individual fields in an jsonb column.
This approach was originally conceived by Joe Hirn in this blog
post.
Validations
Because this gem promotes attributes nested into the JSON column to first level attributes, most validations should just work. Please leave us feedback if they're not working as expected.
请发表评论