Searchkick Aggregations - Need to show Users only from Current.account
My App uses Current.account from ActiveSupport and i need to show only Users (for filtering) who belongs to the Current.account.
The following Setup for Search Filters with Aggregations (searchkick) works so far. BUT:
- it does show all User Records - not only Current.account.users
- when i delete || "*" from the query in the controller i get nothing shown up
Means, i have a serious problem with this kind of "Top Level Scope".
# user.rb
searchkick filterable: [:first_name, :languages, :account]
has_many :user_languages
has_many :languages, through: :user_languages
belongs_to :account
scope :search_import, -> { includes(:account, :languages) }
def search_data
{
account_id: Current.account,
first_name: first_name,
languages: languages.map(&:name)
}
end
# user_controller.rb
def index
query = params[User.where(account_id: Current.account)] || "*"
args = {}
args[:first_name] = params[:first_name] if params[:first_name].present?
args[:languages] = params[:languages] if params[:languages].present?
@users = User.search query, where: args,
aggs: {
first_name: {},
languages: {}
}
end
# users/index.html.erb
<div class="container">
<div class="row">
<div class="col-sm-3">
<div><%= link_to "List All", users_path %></div><br>
<h6>First Name</h6>
<% @users.aggs["first_name"]["buckets"].each do |bucket| %>
<div>
<% if params[:first_name] == bucket["key"].to_s %>
<strong><%= link_to bucket["key"], request.params.except(:first_name) %></strong>
<% else %>
<%= link_to bucket["key"], request.params.merge(first_name: bucket["key"]) %>
<% end %>
(<%= bucket["doc_count"] %>)
</div>
<% end %>
<br>
<h6>Languages</h6>
<% @users.aggs["languages"]["buckets"].each do |bucket| %>
<div>
<% if params[:languages] == bucket["key"].to_s %>
<strong><%= link_to bucket["key"], request.params.except(:languages) %></strong>
<% else %>
<%= link_to bucket["key"], request.params.merge(languages: bucket["key"]) %>
<% end %>
(<%= bucket["doc_count"] %>)
</div>
<% end %>
</div>
<div class="col-sm-9">
<%= render 'user_index' %>
</div>
</div>
</div>
Thanks a lot for a any clue or hint - Cheers.
Bruno,
Make sure you add the account_id in your search's where
so it filters down. ElasticSearch is going to keep a separate indexed copy of your database, so when you search it, you need to apply the same types of filters as you would in your db queries.
@Chris, thanks for fast reply. I am working quite some time on this piece of code - and whatever i try, it does not work. Or in other words: i don't know how to follow your advise and put the stuff together. Some more help is needed, i guess.
I think you just want something like:
def index
query = params[User.where(account_id: Current.account)] || "*"
args = {}
args[:account_id] = Current.account.id
args[:first_name] = params[:first_name] if params[:first_name].present?
args[:languages] = params[:languages] if params[:languages].present?
@users = User.search query, where: args,
aggs: {
first_name: {},
languages: {}
}
end
Thanks mate. I have tried a lot and have been at this point before - but it does not show anything on the index page. I want to show you some server-logs:
using code from above:
User Search (9.8ms) users_development/_search {"aggs":{"first_name":{"filter":{"bool":{"must":[{"term":{"account_id":1}}]}},"aggs":{"first_name":{"terms":{"field":"first_name","size":1000}}}},"languages":{"filter":{"bool":{"must":[{"term":{"account_id":1}}]}},"aggs":{"languages":{"terms":{"field":"languages","size":1000}}}}},"query":{"bool":{"must":{"match_all":{}},"filter":[{"term":{"account_id":1}}]}},"timeout":"11s","_source":false,"size":10000}
this looks fine for account: :{"must":[{"term":{"account_id":1}}]} => exactly what i need, but no User Load and empty view.
Code without query:
User Search (5.0ms) users_development/_search {"aggs":{"first_name":{"filter":{"bool":{"must":[{"term":{"account_id":1}}]}},"aggs":{"first_name":{"terms":{"field":"first_name","size":1000}}}},"languages":{"filter":{"bool":{"must":[{"term":{"account_id":1}}]}},"aggs":{"languages":{"terms":{"field":"languages","size":1000}}}}},"query":{"bool":{"must":{"match_all":{}},"filter":[{"term":{"account_id":1}}]}},"timeout":"11s","_source":false,"size":10000}
using query or not does the same thing, just in half of the time.
kicking out args[:account_id] = Current.account.id
User Search (4.7ms) users_development/_search {"aggs":{"first_name":{"terms":{"field":"first_name","size":1000}},"languages":{"terms":{"field":"languages","size":1000}}},"query":{"match_all":{}},"timeout":"11s","_source":false,"size":10000}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) [["id", 1], ["id", 2], ["id", 3], ["id", 4], ["id", 5], ["id", 6], ["id", 7], ["id", 8], ["id", 9], ["id", 10]]
shows all of the users from all accounts - this is not what i need or want, but it shows, that the setup and view is pretty close to ok, only the scope for Current.account does not filter out the users..
Reindex shows:
User.reindex
User Load (0.5ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1000]]
Account Load (0.4ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" IN ($1, $2) [["id", 1], ["id", 2]]
Userlanguage Load (0.3ms) SELECT "userlanguages".* FROM "userlanguages" WHERE "userlanguages"."user_id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) [["user_id", 1], ["user_id", 2], ["user_id", 3], ["user_id", 4], ["user_id", 5], ["user_id", 6], ["user_id", 7], ["user_id", 8], ["user_id", 9], ["user_id", 10]]
Language Load (0.3ms) SELECT "languages".* FROM "languages" WHERE "languages"."id" IN ($1, $2) [["id", 1], ["id", 2]]
User Import (25.8ms) {"count":10}
=> true
Here i am not sure, if correct - User Load does not list anything?
wow - great! i had a little typo there. now it works perfectly. thanks a lot for super fast help - cheers.