Rails Select from JSON Array
Controller
@venues = JSON.parse @venues
View
<%= select(:model, :venue_id, @venues.map {|v| [ v['venue']['name'], v['venue']['id'] ] }) %>
Or to be more cleaner:
Controller
@venues = JSON.parse @venues
@venues_list = @venues.map { |v| v['venue'] }
View
<%= select(:model, :venue_id, @venues_list.map {|v| [ v['name'], v['id'] ] }) %>
More information about select helper.
Active Record query array of Json
The reason why you're getting a PG::UndefinedFunction:
exception ("operator does not exist: json @> unknown") is because the @> operator is meant to be used in jsonb data type columns, and your products.category
column isn't.
For that you can; or to update the data type of the category
column, or to explicitly cast the column at the moment of performing the query:
Product.where('category::jsonb @> ?', [{ name: 'Sport' }].to_json)
This:
Product.where("category @> ?", "[{'name': 'Sport'}]")
isn't going to work, since it's not valid syntax.
Query on Postgres JSON array field in Rails
Assumptions:
- Postgres 9.4 or later.
- "get all the users that are in serie 5" is supposed to mean:
"with at least one array element that contains{"serie": 5}
. There may be others." - Working with your first, shorter data format. No redundant 'data' key.
Short answer: Use jsonb
instead of json
and this just works:
User.where("groups @> ?", '[{"serie": 5}]')
Note the square brackets to make the right-hand operand a JSON array.
Why?
The prominent misunderstanding here: data type json
is not the same as jsonb
.
You didn't declare the actual table definition, but you later commented json
and there is a hint in the question:
select json_array_elements(groups -> 'data') ->> 'serie' from users;
json_array_elements()
only works for json
, would have to be jsonb_array_elements()
for jsonb
. But you try to use the jsonb
operator @>
which is not defined for json
:
groups -> 'data' @> '?'
The operator ->
returns the same type as the left-hand input. But @>
is only defined for jsonb
, not for json
.
Then you try to use the operator @>
for text
as left-hand operand. Not possible either:
groups ->> 'data' @> ?
There are variants of the operator @>
for various types (incl. Postgres arrays), but not for text
and not for json
.
So, the short answer: Use jsonb
instead of json
. This allows to use very efficient indexes, too:
- Index for finding an element in a JSON array
json
For data type json
you could use:
SELECT *
FROM users u
WHERE EXISTS (
SELECT FROM json_array_elements(u.groups) elem
WHERE elem ->> 'serie' = '5'
);
Demos
jsonb
:
SELECT *
FROM (
VALUES (1, jsonb '[{"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}
, {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]')
, (2, '[{"serie":7, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}
, {"serie":8, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]')
, (3, '[{"serie":9, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}
, {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]')
) users(id, groups)
WHERE groups @> '[{"serie": 5}]';
json
:
SELECT *
FROM (
VALUES (1, json '[{"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}
, {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]')
, (2, '[{"serie":7, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}
, {"serie":8, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]')
, (3, '[{"serie":9, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}
, {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]')
) users(id, groups)
WHERE EXISTS (
SELECT FROM json_array_elements(users.groups) elem
WHERE elem ->> 'serie' = '5'
);
How to query json data with hashes inside array in rails?
With raw SQL you can achieve with the below:
select * from notes,
json_array_elements(items) element
where element->>'description' LIKE '%PM%';
Try the below with activerecord:
Note.where("EXISTS (SELECT FROM json_array_elements(items) element WHERE element->>'description' LIKE '%PM%')")
Ruby on rails and JSON to create Select form
The easiest location to put your JSON file is in the same directory as your controllers -- although doing this kind of thing repeatedly will quickly make a mess out of your controllers folder.
Once you've done that you can read it from your controller like this:
file = File.read('./countries.json')
countries = JSON.parse(file)
and then map countries to the data type that options_for_select
expects.
Once you have that working, I'd recommend making a helper that knows how to read the json file, cache it's data, and return it. Store the json file in the same directory as the helper. Reference the helper in your controller.
Also note: the JSON gem is required for this.
In your helper, you want to create this method:
def countries_for_select
file = File.read('./countries.json')
countries = JSON.parse(file)
countries.map {|c| [ c['country']['label'], v['country']['country_code'] ] })
end
.map
translates the fields from your countries json object to the [[name,key], ...]
array that options_for_select
expects.
Per the form helper on the Rails Documentation, the syntax for select_tag
looks like this
<%= select_tag(:country, options_for_select(...)) %>
but we already created the helper countries_for_select
to match the format that the select_tag
is expecting. So all you need to do is this:
<%= select_tag(:country, countries_for_select) %>
LIKE Query on Postgres JSON array field in Rails
You can do a sub query to get the elements you need to compare and then use them in the where clause:
Message
.from(
Message.select("
id,
headers,
jsonb_array_elements(headers)->>'unparsed_value' AS unparsed_value,
jsonb_array_elements(headers)->>'name' AS name
"), :t
)
.select('t.*')
.where("t.name = 'Subject' AND t.unparsed_value LIKE '%test%'")
Rails query interface: selecting rows in database where any of the JSON array's values match a certain criteria
Since the items
is array at given example you can't work it out using only operators. You need to use jsonb_array_elements()
in order to look into that.
Here's SQL query example to meet your requirement:
SELECT *
FROM publishing_rules
WHERE EXISTS (
SELECT 1
FROM jsonb_array_elements( menu_items -> 'items' )
WHERE value ->> 'id' = '2'
LIMIT 1
);
So, using within WHERE EXISTS
lookup into the array does the trick.
Parse JSON to an Array in Rails
JSON.parse <string>
is probably what you need here. It could look something like this:
test "works" do
get :method
result = JSON.parse(response.body)
assert_equal 1, result.count
end
Check out "How to unit-test a JSON controller?" and the ActiveSupport JSON documention.
Related Topics
Problem Running Thinking Sphinx with Rails 2.3.5
Ruby: Cannot Install Watir Gem on Windows
Multipart Response in Ruby/Rack
The Program 'Rails' Is Currently Not Installed
How to Access a Symbol Hash Key Using a Variable in Ruby
What Is the Advantage of Creating an Enumerable Object Using To_Enum in Ruby
Fresh Install of Rails and Getting Openssl Errors: "Already Initialized Constant Openssl"
How to Assign a Has_Many/Belongs_To Relation Properly in Rails Activerecord
Creating a Gmail Draft with Recipients Through Gmail API
Exec the Cd Command in a Ruby Script
Ruby on Rails Active Admin Has_Many Changing Dropdown to Use a Different Column
Can't Install Ruby via Rvm, Error Running '_Rvm_Make -J4' on Ubuntu 22.04
How to Parse Xml Nodes to CSV with Ruby and Nokogiri
How to Convert 1 to "First", 2 to "Second", and So On, in Ruby
Flash Message with HTML_Safe from the Controller in Rails 4 (Safe Version)
How to Change Environment Variables When Running Rspec for Ruby