I have a collection with a string field called named in my Mongoid based class. I'd like to be able to query for all documents that begin with the letters in the a through f in the name field, case insensitive. What's the best way to do this through Mongoid? I'm assuming the interface is similar to ActiveRecord, so if it can be done in ActiveRecord, it can probably be done through Mongoid as well.
This will do the trick
Yourcollection.where(:name => /^[a-f]/i )
i - for case insensitive
Related
I have array of strings:
a = ['*#foo.com', '*#bar.com', '*#baz.com']
I would like to query my model so I will get all the records where email isn't in any of above domains.
I could do:
Model.where.not(email: a)
If the list would be a list of strings but the list is more of a regexp.
It depends on your database adapter. You will probably be able to use raw SQL to write this type of query. For example in postgres you could do:
Model.where("email NOT SIMILAR TO '%#foo.com'")
I'm not saying thats exactly how you should be doing it but it's worth looking up your database's query language and see if anything matches your needs.
In your example you would have to join together your matchers as a single string and interpolate it into the query.
a = ['%#foo.com', '%#bar.com', '%#baz.com']
Model.where("email NOT SIMILAR TO ?", a.join("|"))
Use this code:
a = ['%#foo.com', '%#bar.com', '%#baz.com']
Model.where.not("email like ?",a.join("|"))
Replace * to % in array.
ActiveRecord's .where() query method supports interpolation like this:
Book.where("author_id IS ? AND genre_id IS ?", author_id, genre_id)
Does the .select() method support similar interpolation, or would we need to use standard Ruby string interpolation (e.g. "WHEN genre_id IS #{genre_id} THEN 2").
(This might seem like a far-fetched use case, but essentially we're building a query with a calculated field - SUM() as sum for example - which uses different values depending on each record's fields, via a CASE statement, and we'd like to avoid hard-coding values into the query.)
I'm interested in all answers, but this particular application happens to still be on Rails 3.2.x.
You can use one of the ActiveRecord::Sanitization for this:
def self.select_with_params(sql, params = [])
query = sanitize_sql_array([sql, params].flatten)
select(query)
end
And use this method inside AR chaining:
User.where(name: 'name').select_with_params("name='%s' and group_id='%s'", "foo'bar", 4)
I have a table called items with a type column.
This column can have one of the following values:
rock
paper
scissor
Inside my translation file:
en:
rock: Stone
paper: Wood
scissor: Weapon
How can i fetch the results and order them by the translated value using ActiveRecord?
Obviously, if I do Item.where(something: true).order('name asc') I would get the results ordered by the value inside the database (rock) and not the translated value (Stone).
I am aware of some ruby methods such as sort_by and sort to order items with ruby, but I would like to order the results in ActiveRecord for performance reasons.
I managed to solve this by using a CASE statement.
Item.select("*,
CASE
WHEN type = 'rock' THEN '#{I18n.t(:rock)}'
WHEN type = 'paper' THEN '#{I18n.t(:paper)}'
WHEN type = 'scissor' THEN '#{I18n.t(:scissor)}'
END AS translated_type
")
.where(something: true)
.order('translated_type asc')
This works fine in my case since I know which types to expect.
Is there a way to set an attribute in mongoid for case insensitive searches?
Lets say that somebody has a username: IAmGreat and I want to find the users data using their unique username without butchering it and changing it to iamgreat.
Thanks
Actually you can search case insensitive. But you have to search with an regex!
Here is an example how I'm using it at http://zeit.io
User.where(email: /\A#{Regexp.escape(email)}\z/i).first
With the / you are starting and ending the regex. The i after the regex means case insensitive. \A Means the string has to start with the search string and \z means the string has to end with the search string. This is important if you are looking for an exact match.
You can even try something like:
User.where(username: /#{username}/i).first
if you are using rails or mongoid you can try the ff:
#user = User.where({:username => /.*#{name}.*/i })
Why not just down a User.login.downcase (or whatever your model/attribute combination is) when making the comparison? This will leave the capitalization in the DB as-is, but downcase the field just for comparison.
If your application doesn't need to store user-input as case-sensitive, just convert the input to uppercase or lowercase on the way in. Example,
username = params[:username].to_s.downcase
Otherwise, if performance is an issue for you (case-insensitive regex cannot take advantage for indexes) the right way to go about it is to store a backup field for username
field :username_downcase
And then do the query:
User.where(username_downcase: params[:username].to_s.downcase)
I am using Sphinx with the Thinking Sphinx plugin to search my data. I am using MySQL.
My data contains accented chars ("á", "é", "ã") and I want them to be equivalent to their non-accented counterparts ("a", "e", "a", for example) when searching and ordering.
I got the search working using a charset table (pastie.org/204316), and a search for "AGUA" returns "ÁGUA", but the ordering of the results is not working properly. In a search for "AGUA", "ÁGUA" cames after "MUITA ÁGUA", for example, but I wanted it to be sorted as if it were written with an "A", not an "Á".
The only solution I can think is index a new column containing the non-accented chars and using it for sortering, using the REPLACE (http://dev.mysql.com/doc/refman/5.4/en/string-functions.html#function_replace) mysql function to strip the accented chars, but I would need one call to REPLACE for each possible accented char (and there are many) and it seems to me a not very maintanable workaround.
Anybody know some better way to handle this issue?
Thanks!
Sphinx handles sorting on string fields by storing all the values in a list, sorting the list and then storing the index of each string as an int attribute. According to the docs the sorting of this list is done at a byte level and currently isn't configurable.
Ideally the strings should be sorted differently, depending on the encoding and locale. For instance, if the strings are known to be Russian text in KOI8R encoding, sorting the bytes 0xE0, 0xE1, and 0xE2 should produce 0xE1, 0xE2 and 0xE0, because in KOI8R value 0xE0 encodes a character that is (noticeably) after characters encoded by 0xE1 and 0xE2. Unfortunately, Sphinx does not support that at the moment and will simply sort the strings bytewise.
-- from http://www.sphinxsearch.com/docs/current.html
So, no easy way to achieve this within Sphinx. A modification to your REPLACE() based idea would be to have a separate column and populate it using a callback in your model. This would let you handle the replace in Ruby instead of MySQL, an arguably more maintainable solution.
# save an unaccented copy of your title. Normalise method borrowed from
# http://stackoverflow.com/questions/522715/removing-accents-diacritics-from-string-while-preserving-other-special-chars-tri
class MyModel < ActiveRecord::Base
before_validation :update_sort_col
private
def update_sort_col
sort_col = self.title.to_s.mb_chars.normalize(:kd).gsub(/[^-x00-\x7F]/n, '').to_s
end
end
you can also use a special index for that you dont even need a new column on your db
indexes "LOWER(title)", :as => :title, :sortable => true
its raw sql so you can call your replace method.
Just build index on lower case version with following syntax. Its very simple and elegant solution for case insensitive search using Sphinx.
indexes title, as: :title, sortable: :insensitive