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 78,890+ developers who get early access to new tutorials, screencasts, articles, and more.

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

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2023 GoRails, LLC. All rights reserved.