Search in rails serialize column - ruby-on-rails

I know it's bad to search in serialize, but I encounter this problem.
I got a model called Question and contain a serialize column assignments
id question_set_id assignments
1 1 {"12982": true, "12332": true}
2 2 {"12222": true, "12332": true}
3 3 {'11111': true}
And I got a array called group_ids
group_ids = ["12982","12332"]
I need to find the record who contain at least one group_id in assignments.
So, the result of this example should be like
[
{
:id => 1,
:question_set_id => 1,
:assignments => {"12982": true, "12332": true}
},
{
:id => 2,
:question_set_id => 2,
:assignments => {"12222": true, "12332": true}
}
]
I've tried
Question.where("assignments IS NOT NULL").where("assignments LIKE '%?%'", 12982)
It seems works, but how to apply an array?
And according this answer, I tried
Question.where("assignments IS NOT NULL").where("assignments= ?", groups_ids.to_yaml)
However, it return a blank array.

With mysql 5.7.? you can query JSON data directly. I didn't try it but following the docs something like
Question.where("JSON_CONTAINS_PATH(assignments , 'one', '$[*].assignments.12982', '$[*].assignments.12332') == 1")
should work. You can furthor more convert your column from text to JSON data type and get validation of the json document and optimized storage.

Related

Sort Elasticsearch results by integer value via Searchkick

I'm working on a Rails application that uses Searchkick as an interface to Elasticsearch. Site search is working just fine, but I'm running into an unexpected issue on a page where I'm attempting to retrieve the most recent recoreds from Searchkick across a couple different models. The goal is a reverse chronological list of this recent activity, with the two object types intermingled.
I'm using the following code:
models = [ Post, Project ]
includes = {
Post => [ :account => [ :profile ] ],
Project => [ :account => [ :profile ] ],
}
#results = Searchkick.search('*',
:models => models,
:model_includes => includes,
:order => { :id => :desc },
:limit => 27,
)
For the purposes of getting the backend working, the page in development is currently just displaying the title, record type (class name), and ID, like this:
<%= "#{result.title} (#{result.class} #{result.id})" %>
Which will output this:
Greetings from Tennessee! (Post 999)
This generally seems to be working fine, except that ES is returning the results sorted by ID as strings, not integers. I tested by setting the results limit to 1000 and found that with tables containing ~7,000 records, 999 is considered highest, while 6905 comes after 691 in the list.
Looking through the Elasticsearch documentation, I do see mention of sorting numeric fields but I'm unable to figure out how to translate that to the Seachkick DSL. It this possible and supported?
I'm running Searchkick 4.4 and Elasticsearch 7.
Because Elasticsearch stores IDs as strings rather than integers, I solved this problem by adding a new obj_id field in ES and ordering results based on that.
In my Post and Project models:
def search_data
{
:obj_id => id,
:title => title,
:content => ActionController::Base.helpers.strip_tags(content),
}
end
And in the controller I changed the order value to:
:order => { :obj_id => :desc }
The records are sorting correctly now.

How do I get data from Arel output?

I'm successfully following some of the commands listed here and applying them to my own tables.
How do I turn the output into actual records/data ? Presently it's returning some output which I can assign to a variable, but I do not understand this output at all.. it doesn't look like an array or hash (but perhaps it is), and I do not understand how to access its contents (I want to use the output in a rails view, but at the least would like to access the table records in the console where I'm executing the Arel code)
For example, say I have two tables; User and Product as follows:
User = [{:id => 1, :name => "Joe", :email => "joe#gmail.com"}, {:id => 2, :name => "Jane", :email => "jane#gmail.com"}]
Product = [{:product_name => "Car Tire", :brand => "BMW", :last_edited_by => 1}, {:product_name => "Paint Brush", :brand => "Dulux", :last_edited_by => nil}, {:product_name => "Dog Biscuits", :brand => "Bowow Snacks", :last_edited_by => 2}, {:product_name => "Game", :brand => "Westwood", :last_edited_by => 1}]
Suppose I want to join the two tables User.id = Product.last_edited_by
In SQL it would be as simple as:
SELECT *
FROM User
JOIN Product
WHERE users.id = products.last_edited_by
Now if I plug this into scuttle.io to convert to Arel, it gives:
User.select(Arel.star).where(
User.arel_table[:id].eq(Product.arel_table[:last_edited_by])
).joins(
User.arel_table.join(Product.arel_table).on(null).join_sources
)
But trying this returns: ArgumentError: wrong number of arguments (given 1, expected 0)
Attempting to emulate advice given here, I come up with another approach:
users.project(Arel.star).join(User).on(Product[:last_edited_by].eq(User[:id]))
But this returns: NoMethodError: undefined method `project' for Array..
A final point, if I run
users = Arel::Table.new(User)
output = users.project(users[:id].as("id"), users[:id].count.as("count")).group("id")
I get some output which looks almost meaningful, but I don't know how to return that into something I can make sense of, and I wouldn't know how to use it if I provided it to a rails view

Can't access data in ActiveHash

I'm using the Gem active_hash https://github.com/zilkey/active_hash to create models for simple data that I don't want to create DB tables for.
For example, I have this model setup for FieldTypes:
class FieldType < ActiveHash::Base
self.data = [
{:id => 1, :name => "text", :friendly_name => "Text"},
{:id => 2, :name => "textarea", :friendly_ => "Text Area"},
{:id => 3, :name => "image", :friendly_ => "Image"},
]
end
And I'm trying to list these field types for a select:
def field_types_for_select
#FieldType.all.order('name asc').collect { |t| [t.friendly_name, t.name] }
FieldType.pluck(:friendly_name, :name)
end
But I get an error that order, collect or pluck are not defined.
How do I access this data? This works fine on other models, just not ActiveHash ones. According to the docs the model should work the same as ActiveRecord but I don't seem to be able to access it the same. FieldType.all works, but other methods do not.
Pluck isn't defined on ActiveHash::Base. It is defined on ActiveRecord::Relation::Calculations, and it's purpose is to produce a SQL select for the columns you specify. You will not be able to get it to work with ActiveHash.
You can, however, define your own pluck on your FieldType model.
def self.pluck(*columns)
data.map { |row| row.values_at(*columns) }
end
Or query the data directly:
FiledType.data.map { |row| row.values_at(:friendly_name, :name) }

Ruby on rails searching arrays (Active record)

I have a model with an array column. So I'm basically saving languages as an array to Postgres. For example, driver_language =["English", "Spanish", "French"]
In my Query, I want to select all vehicles where submitted_driver_language ["English", "Spanish"] is included in driver_language. Or at least one element of the submitted driver_language array is included in the driver_language column which is an array. How can I add that condition to the query below? Any help will be appreciated
Vehicle.where(:vehicle_type => vehicle_type, :active => true, :company_activated => true, :capacity => number_of_people.to_i..Float::INFINITY)
Use arel_table.
#vehicle = Vehicle.where(:vehicle_type => vehicle_type, :active => true, :company_activated => true, :capacity => number_of_people.to_i..Float::INFINITY)
avehicle = #vehicle.arel_table
#required_result = #vehicle.where(avehicle[:driver_language].matches('%#{"English", "Spanish"}%'))
What about a regex?
Vehicle.where('driver_language ~* ?', 'english|spanish')

Should dates be an embedded document?

I am using Mongoid 3. I have a Video model. Should dates be an embedded document or an Array type?
If I have this structure:
{
:id => 2,
:dates => [
{
:date => Time.now.strftime('%Y%m%d').to_i,
:views => {
:non_uniques => 1,
:uniques => 1,
:countries => {
:us => 1,
:uk => 1
}
},
:likes => 1,
:comments => 1,
}
]
}
Moreover, should views, countries be an embedded document?
As you are planning to capture the additional information with the date , i think your current schema is correct . One aspect is also need to be consider , how you are going to use the data or query. If you want to see the total views and likes for a video for particular date i think your approach is correct , but if you are going to show overall likes and view rather than daily then array will be better. It is typically what you are doing is correct from the sense of NoSQL and embedded document but in last it all depends what all you want to query . Here your reading of daily statistic will be very fast.

Resources