Searchkick, how to use aggregations on a join table - searchkick

I'm a searchkick newbie.
I read the docs and I understand how to use aggregations, and I also watch some video.
Every tutorial I read uses aggregation on attributes on the main indexed model.
By the way I understand that I can use also aggregation on associations.
But my situation is different.
I have a complex situation
class Product < ProductDatabase::Base
searchkick
has_many :products_features
end
class ProductFeature < ProductDatabase::Base
belongs_to :product
belongs_to :feature
end
class Feature < ProductDatabase::Base
has_many :products
end
ProductsFeatures is the join table between the features and the products, and in the join table I have the values I need in my aggregations...
t.string "raw_value"
t.string "presentional_value"
t.integer "product_id"
t.integer "feature_id"
t.boolean "searchable", default: false
Example:
For every category of products, for example, "smartphone", I need to add an aggregate search for the display size.
The smartphone display sizes for every product in my database is inside the ProductsFeatures table, with a specific feature_id (the one that corresponds to the display size).
I already create a search system with activerecord query and it works, but every time I need to manually add the part of the code I need to filter results.
I'm starting to learn ElasticSearch and SearchKick and I want to use a project that I already have...

Related

How to design MongoDB collection relation correctly

I am trying to create a simple DB of Customers/Products/Orders to practice my skills with aggregate and so on. I need some help on how to design the relation between those collections correctly (that i'll really be able to store the details in the right way).
I go for the minimal build and information-->
Customer:
(1) customer_id ,
(2)orders (this will be an array with all the order_id's this customer did)
Product:
(1) product_id
Order:
(1) order_id ,
(2) products (this will be an array with all the products in this order) + I wonder how I add quantity for each product ,
(3) user_id (this will store the user_id did this order) or i don't even need this field??
I hope someone could tell me if this is a right thinking, because I come from SQL and this what I would do there I guess
// I'm not using embedded document because in case i'll want to change a specific field value it would change in all places

Rails 4+: only select specific columns from an included association

I have a user model that belongs to to an account (pretty standard). On every request, I need to retrieve the current_user but I also want to return the account to reduce DB queries:
# ApplicationController
def current_user
#current_user ||= User.includes(:account).find_by(auth_token: cookies[:auth_token])
end
def current_account
#current_account ||= current_user.account
end
This works just fine. However, the account record has a lot of extra text data that I don't always want to return. A more permanent solution would be to move those extra fields to a new table called account_details and have a one-to-one between an account and account_details.
However, I need a shorter-term solution that will provide some optimizations until I can refactor that (perfection is an iterative process!).
I want to return ALL columns from the current_user, but I only want to select a few columns from the current_account.
I tried this and I didn't work:
#current_user ||= User.includes(:account).references(:account).select("users.*, account.id, account.uuid").find_by(auth_token: cookies[:auth_token])
When I look at #current_user.account it still displays all the columns with their values and I only wanted the id, uuid columns.
I couldn't find any clear syntax on using select(...) with includes(:association); is this something that's possible?
You need to add an extra association in your User model.
belongs_to :account_columns, -> { select(:id, :uuid) }, class_name: 'Accoun'
This association should be used in your query.
User.includes(:account_columns)
This is because Rails don't have the facility to pass the options for include query.
Also consider using join instead includes in your query, as it also caters your need.
User.joins(:accounts).select("accounts_ids, accounts.uuid")

Multiple mappings per ActiveModel/Record?

Lets say I want to create two separate indexes on something like BlogPosts, so that I can do a quick search using one index (for autocomplete purposes for example) then use the other index for full blown search querying.
Is that something I can do with Tire?
so something like this (forgive me if its a little primitive)
class Post < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
index_name 'autocomplete'
mapping do
indexes :title, :analyzer => 'my_ngram_analyzer'
end
index_name 'main'
mapping do
indexes :title
indexes :description
indexes :author
indexes :published_on
end
end
where the callbacks know to add and remove new posts from the appropriate indexes
You can't do this in Tire, setting two separate indices (and mappings) in one class with the mapping DSL method.
It may be a good idea to use two separate indices, one for auto-completion, another for search. There's a nice tutorial, StackOverflow answer and even an elasticsearch plugin to get you started.
However, unless you have a lot of data, you'd be able to achieve that even with a single index, using the multi_field type, match query across multiple fields, and potentially an NGram based analyzer.
Check out the Autocomplete with Tire tutorial which outlines the approach.
Cross-post from https://github.com/karmi/tire/issues/531

rails 3.1 complex find_by_sql query on nested has_many through models

My simplified rails app looks like this
# chapter.rb
has_many :sections
has_many :videos, through: :sections
# section.rb
belongs_to :chapter
has_many :videos
# video.rb
belongs_to :section
has_many :votes
# vote.rb
belongs_to :video
What I want to do is find the top 5 currently popular videos for a given chapter, which would mean ordering the videos by the number of votes it has received within the last month (and limiting to 5 results, obviously).
I wanted to write a popular_videos method in my Chapter model, and I think this requires a find_by_sql query, right? But I don't know enough sql to write this query.
The votes table has a created_at column, and I'm using postgres for my database. Any help is greatly appreciated.
I don't know anything about rails, but guessing at the table structures from what's in the question, I would think SQL like the following would be one way to provide what you want:
SELECT video.id, video.name, count(*) as vote_count
FROM video JOIN vote ON (video.id = vote.video_id)
WHERE vote.date > (current_date - interval '1 month')
GROUP BY video.id, video.name
ORDER BY vote_count DESC
LIMIT 5;
If you're running PostgreSQL 9.1 or later, you can probably omit video.name from the GROUP BY list.

How to order documents by a dynamic property in Mongoid

I am using Mongoid to store a series of geocoded listings. These listings need to be sorted by price and proximity. The price of every listing is a field in the database whereas distance is a dynamic property that is unique for every user.
class Listing
include Mongoid::Document
field :price
def distance
get_distance(current_user.location,coordinates)
end
end
How can I sort these documents by distance? I tried #listing.desc(:distance) and that didn't work.
The short (and unhelpful) answer is: you can't.
Mongoid does have the ability to query based on 2d co-ordinates though, then you could update your controller to do something like this:
#listings = Listing.near(current_user.location)
Which I believe will return your listings in order of distance.
On a side note, I noticed that your Listing model is referring to your current_user object, which kinda breaks the MVC architecture, since your models shouldn't know anything about the current session.