Ask A Question

Notifications

You’re not receiving notifications from this thread.

Searchkick Aggregations - Need to show Users only from Current.account

Bruno Steinmann asked in Rails

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.

Reply

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.

Reply

@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.

Reply

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
Reply

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?

Reply

Have you double checked to make sure you're indexing the account_id in ElasticSearch?

Reply

wow - great! i had a little typo there. now it works perfectly. thanks a lot for super fast help - cheers.

Reply

Awesome! I like when solutions are that easy. 🤘

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 82,464+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.