search double case in mongodb in Ruby on rails - ruby-on-rails

here my code in model is
def self.search(search)
if search
where(name: /#{Regexp.escape(search)}/i)
else
scoped
end
end
Now i want to add another field also to search
like
where(price: /#{Regexp.escape(search)}/i)
So my query should search two field
like
where(name: /#{Regexp.escape(search)}/i) (or) where(price: /#{Regexp.escape(search)}/i)
How to add this two field in mongodb like or . Working example is accepted.
Since i have less knowledge about mongodb.

If you are using Mongoid 3, you can write your query like this:
self.or({name: /#{Regexp.escape(search)}/i}, {price: /#{Regexp.escape(search)}/i})
If you are using something other than Mongoid 3 (like MongoMapper or Mongoid 2), please give the name and version number.
Source: Selection syntax docs for Mongoid 3 are here.

Try this where('$or' => [{"name" => "/#{Regexp.escape(search)}/i"}, {"price" => "/#{Regexp.escape(search)}/i"}])

Related

ActiveRecord Fuzzy Search

I'm looking to perform a search to find an object similar to this:
Object(id: 1, example: "abc")
by using a search like this:
params[:search] = "abcdef"
Object.where("example LIKE ?", "#{params[:search]%")
but am only able to use the above example if my search has less characters than my object, not more.
I think it should be
params[:search] = "abcdef"
Object.where("example LIKE ?", "%#{params[:search]}%")
Also might want to use ilike for case insensitive search (if you're using postgres)
Note: the fuzzily gem does not work with Rails 6. This solution has been deprecated.
The fuzzily gem allows you to do fuzzy searching of ActiveRecord models that you've instrumented appropriately.
Fuzzily finds misspelled, prefix, or partial needles in a haystack of strings. It's a fast, trigram-based, database-backed fuzzy string search/match engine for Rails.
Once you've installed the gem, you can instrument your model as follows:
class MyStuff < ActiveRecord::Base
# assuming my_stuffs has a 'name' attribute
fuzzily_searchable :name
end
You can then perform fuzzy searches as follows:
MyStuff.find_by_fuzzy_name('Some Name', :limit => 10)
# => records

Activeadmin: how to filter for strings that match two or more search terms

Let's say I've got User class with an :email field. And let's say I'm using activeadmin to manage Users.
Making a filter that returns emails that match one string, e.g. "smith", is very simple. In admin/user.rb, I just include the line
filter :email
This gives me a filter widget that does the job.
However, this filter doesn't let me search for the intersection of multiple terms. I can search for emails containing "smith", but not for emails containing both "smith" AND ".edu".
Google tells me that activerecord uses Ransack under the hood, and the Ransack demo has an 'advanced' mode that permits multiple term searches.
What's the easiest way to get a multiple term search widget into activeadmin?
Ideally, I'd like a widget that would allow me to enter smith .edu or smith AND .edu to filter for emails containing both terms.
there is simple solution using ranasckable scopes
So put something like this in your model
class User < ActiveRecord::Base
....
scope :email_includes, ->(search) {
current_scope = self
search.split.uniq.each do |word|
current_scope = current_scope.where('user.email ILIKE ?', "%#{word}%")
end
current_scope
}
def self.ransackable_scopes(auth_object = nil)
[ :email_includes]
end
end
After this you can add filter with AA DSL
Like
filter :email_includes, as: :string, label: "Email"
UPD
should work if change email_contains_any to email_includes
I've figured out a solution but it's not pretty.
The good news is that Ransack has no trouble with multiple terms searches. These searches use the 'predicate' cont_all. The following line works for finding emails containing 'smith' and '.edu'.
User.ransack(email_cont_all: ['smith','.edu'] ).result
Since these searches are easy in Ransack, they're probably straightforward in Activeadmin, right? Wrong! To get them working, I needed to do three things.
I put a custom ransack method (a.k.a. ransacker) into User.rb. I named the ransacker email_multiple_terms.
class User < ActiveRecord::Base
# ...
ransacker :email_multiple_terms do |parent|
parent.table[:path]
end
I declared a filter in my activeadmin dashboard, and associated it with the ransacker. Note that the search predicate cont_all is appended to the ransacker name.
admin/User.rb:
ActiveAdmin.register User do
# ...
filter :email_multiple_terms_cont_all, label: "Email", as: :string
This line creates the filter widget in Activeadmin. We're nearly there. One problem left: Activeadmin sends search queries to ransack as a single string (e.g. "smith .edu"), whereas our ransacker wants the search terms as an array. Somewhere, we need to convert the single string into an array of search terms.
I modified activeadmin to split the search string under certain conditions. The logic is in a method that I added to lib/active_admin/resource_controller/data_access.rb.
def split_search_params(params)
params.keys.each do |key|
if key.ends_with? "_any" or key.ends_with? "_all"
params[key] = params[key].split # turn into array
end
end
params
end
I then called this method inside apply_filtering.
def apply_filtering(chain)
#search = chain.ransack split_search_params clean_search_params params[:q]
#search.result
end
This code is live in my own fork of activeadmin, here: https://github.com/d-H-/activeadmin
So, to get multiple term search working, follow steps 1 and 2 above, and include my fork of A.A. in your Gemfile:
gem 'activeadmin', :git => 'git://github.com/d-H-/activeadmin.git'
HTH.
If anyone's got a simpler method, please share!
Just add three filters to your model:
filter :email_cont
filter :email_start
filter :email_end
It gives you a flexible way to manage your search.
This filter executes next sql code:
SELECT "admin_users".* FROM "admin_users"
WHERE ("admin_users"."email" ILIKE '%smith%' AND
"admin_users"."email" ILIKE '%\.edu')
ORDER BY "admin_users"."id" desc LIMIT 30 OFFSET 0
I expect that exactly what you're looking for.

how to rank records dynamically in a result set in rails using sunspot solr

I have users, cafes and their food_items(which have some ingredients listed). Until now i used solr to search for food_items via some ingredients that a user likes. This was accomplished using sunspot-solr search according to the sunspot docs
Also, i am able to gather a relative like-ness of a user to different cafes(based on how many times he has visited it, searched its menu etc)(this is a dynamic value that will be generated on the fly)
Problem:
I want to show the same results(food_items) fetched via solr, ranked by cafes(result re-ranking)(based on the like-ness of the user to a cafe) using sunspot solr for rails
This app is hosted on heroku and uses websolr
i have found these:
https://cwiki.apache.org/confluence/display/solr/Query+Re-Ranking
https://cwiki.apache.org/confluence/display/solr/RankQuery+API
but i have no idea as to how i can create a QParserPlugin or generate a rank query in sunspot.
sunspot provides a way to write custom queries. so if i could get help in constructing a query to fetch the like-ness and rank each record (or) any other way to implement such logic, that would be great. thanks!
you can do something like:-
def build_query(where_conditions)
condition_procs = where_conditions.map{|c| build_condition c}
Sunspot.search(table_clazz) do
condition_procs.each{|c| instance_eval &c}
paginate(:page => page, :per_page => per_page)
end
end
def build_condition(condition)
Proc.new do
# write this code as if it was inside the sunspot search block
keywords condition['words'], :fields => condition[:field].to_sym
end
end
conditions = [{words: "tasty pizza", field: "title"},
{words: "cheap", field: "description"}]
build_query conditions

Texticle and ActsAsTaggableOn

I'm trying to implement search over tags as part of a Texticle search. Since texticle doesn't search over multiple tables from the same model, I ended up creating a new model called PostSearch, following Texticle's suggestion about System-Wide Searching
class PostSearch < ActiveRecord::Base
# We want to reference various models
belongs_to :searchable, :polymorphic => true
# Wish we could eliminate n + 1 query problems,
# but we can't include polymorphic models when
# using scopes to search in Rails 3
# default_scope :include => :searchable
# Search.new('query') to search for 'query'
# across searchable models
def self.new(query)
debugger
query = query.to_s
return [] if query.empty?
self.search(query).map!(&:searchable)
#self.search(query) <-- this works, not sure why I shouldn't use it.
end
# Search records are never modified
def readonly?; true; end
# Our view doesn't have primary keys, so we need
# to be explicit about how to tell different search
# results apart; without this, we can't use :include
# to avoid n + 1 query problems
def hash
id.hash
end
def eql?(result)
id == result.id
end
end
In my Postgres DB I created a view like this:
CREATE VIEW post_searches AS
SELECT posts.id, posts.name, string_agg(tags.name, ', ') AS tags
FROM posts
LEFT JOIN taggings ON taggings.taggable_id = posts.id
LEFT JOIN tags ON taggings.tag_id = tags.id
GROUP BY posts.id;
This allows me to get posts like this:
SELECT * FROM post_searches
id | name | tags
1 Intro introduction, funny, nice
So it seems like that should all be fine. Unfortunately calling
PostSearch.new("funny") returns [nil] (NOT []). Looking through the Texticle source code, it seems like this line in the PostSearch.new
self.search(query).map!(&:searchable)
maps the fields using some sort of searchable_columns method and does it ?incorrectly? and results in a nil.
On a different note, the tags field doesn't get searched in the texticle SQL query unless I cast it from a text type to a varchar type.
So, in summary:
Why does the object get mapped to nil when it is found?
AND
Why does texticle ignore my tags field unless it is varchar?
Texticle maps objects to nil instead of nothing so that you can check for nil? - it's a safeguard against erroring out checking against non-existent items. It might be worth asking tenderlove himself as to exactly why he did it that way.
I'm not completely positive as to why Texticle ignores non-varchars, but it looks like it's a performance safeguard so that Postgres does not do full table scans (under the section Creating Indexes for Super Speed):
You will need to add an index for every text/string column you query against, or else Postgresql will revert to a full table scan instead of using the indexes.

How do I get the search to use the attr_accessor?

Ok so i have a date field that i need to search on, but i need to search on it by day like in a mysql query
search_conditions << ["DAY(open_date) != ?", event.thursday.day] if options[:thur].blank?
and i need to do this condition with Thinking Sphinx so i tried this
attr_accessor :event_day
def event_day
self.start_date.day
end
#thinking sphinx configurations for the event search
define_index do
indexes event_day
...
...
and in the search i tried this
search_string = "#event_day -#{event.thursday.day}" unless options[:thur].blank?
but i keep getting this error
index event_core: query error: no field 'event_day' found in schema
Any way to make this work
You can't use a ruby attribute in an SQL query. Rails isn't that clever.
You need to write SQL that replicates that function, or filter the results of a query through it, e.g.
#my_query.where(:a => "b").select { |rec| rec.some_method == "some value" }
As Michael's pointed out, Ruby attributes aren't accessible by Sphinx - it talks directly to your database.
So, either you can create a column that holds the event day value, and reference that via Sphinx, or you can create a field that uses a SQL function (which could vary, depending on MySQL or PostgreSQL) that extracts the day from the start_date column - not particularly complex. It'd probably end up looking like this:
indexes "GET_DAY_FROM_DATE(start_date)", :as => :event_day

Resources